Live data from Hacker News

C: Simple Defer, Ready to Use

gustedt.wordpress.com

131–140 of 157 posts

Re: C: Simple Defer, Ready to Use

#131
post #130
post #92

One big flaw in Go-style `defer` is that error handling and scoping are an afterthought, and it's disappointing to see this is not improved upon in this proposal (at least as I understand the proposal). I do think this matters in practice. If I have a `func whatever() error` IME it's a common to accidentally do something like `defer whatever()` without catching handling the error. To work around that you'd need to do…

> One big flaw in Go-style `defer` is that error handling and scoping are an afterthought.... Like many other things in Go's approach to language design, still better than using plain old C, though.

Yes, for better or for worse, I think the ethos of Go is pretty much "a mulligan on C". Every C project re-implements a bespoke hash table, struggles with Unicode strings, spends a lot of time on memory management, gets tripped up on dynamic linking, and so on. If otherwise like C but are tired of those things, guess which language is perfect for you?

Re: C: Simple Defer, Ready to Use

#132
post #125
post #97

Earlier quoted context omitted.

Why do you think you need executable stacks for nested functions? I don't know what GCC is doing, but functional programming languages usually 'compile away' the nesting of functions fairly early, see https://en.wikipedia.org/wiki/Lambda_lifting Update: Oh, I see, it's because GCC doesn't want to change how function are passed around ('function pointers' in C speak), so they need to get creative. Functional languages…

GCC creates trampolines only when it needs the address of the nested function, which it does not in this case (formally it does but not really). Also new version can place the trampoline on the heap (-ftrampline-impl=heap) and then you also need no executable stack. I wide pointer would be better though.

> Also new version can place the trampoline on the heap (-ftrampline-impl=heap) and then you also need no executable stack. I wide pointer would be better though.

Wouldn't you need an executable heap, though?

(That's not as outlandish, because eg a JIT would need that to. But most straightforward C programs don't need to create any executable memory contents at runtime.)

Re: C: Simple Defer, Ready to Use

#133
post #128

Earlier quoted context omitted.

When constructing an object in C, we may need some permanent sub-objects, and some temporary objects. If we only need permanent sub-objects, then we set those up gradually, and build an error path in reverse order (with gotos or with the arrow pattern); upon success, the sub-objects' ownership is transferred to the new super-object, and the new super-object is returned, just before the error path is reached. Otherwis…

So, you recommend using goto, which indeed is the only available mechanism.

> using goto, which indeed is the only available mechanism.

There are other options, but none of them is better, IMO. You can use nested functions:

    char * p = malloc(10);
    if(p!=0) {
      doTheRealWork(p);
    };
    free(p);
In gcc, doTheRealWork can be a nested function or it you can force them to be inlined.

You can also (more readable than that first alternative, IMO) wrap code in a single-iteration for or while loop and then use break to exit it:

  char *p = null;
  for(int i=0;i==0;i=1) {
    p = malloc(10);
    if(p==0) break;
    …
  }
  free(p);
Both will get uglier if you need to free multiple resources, but will work.

Re: C: Simple Defer, Ready to Use

#134
post #25

The C++ lambda version can be a foot gun: https://godbolt.org/z/Wd66GcrdG , if the return value is a struct, NRVO (named return value optimization) may be applied and the lambda will be called in different order. As for the n3434 proposal, given that the listed implementation experiences are all macro-based, wouldn't it be more easily adopted if proposed as a standard macro like ?

OMG!

returns_struct looks actually correct to me, ie it is expected (by me). Golang's defer works this way.

Do both examples follow standard? Or is it common misinterpretation by all compilers?

Re: C: Simple Defer, Ready to Use

#135
post #132
post #125

Earlier quoted context omitted.

GCC creates trampolines only when it needs the address of the nested function, which it does not in this case (formally it does but not really). Also new version can place the trampoline on the heap (-ftrampline-impl=heap) and then you also need no executable stack. I wide pointer would be better though.

> Also new version can place the trampoline on the heap (-ftrampline-impl=heap) and then you also need no executable stack. I wide pointer would be better though. Wouldn't you need an executable heap, though? (That's not as outlandish, because eg a JIT would need that to. But most straightforward C programs don't need to create any executable memory contents at runtime.)

It does use executable heap space, but I think it uses specific pages which might also be pre-initialized, but I need to check how they implemented it.

Re: C: Simple Defer, Ready to Use

#136
post #52
post #41

Earlier quoted context omitted.

No it doesn't; C functions don't set up appropriate registrations with the C++ exception / stack unwinding systems, thus C functions are simply skipped over on the way up towards the nearest exception handler. __attribute__((cleanup(…))) is purely a scope-local mechanism, it has absolutely nothing to do with exceptions.

"If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally." [1] While it's true that it -fexceptions is disabled for C by default, some C libraries need to enable i…

Ah, I forgot about -fexceptions, Thanks. Though I need to point out it's non-default and rarely used, and in particular:

> some C libraries need to enable it anyway if they want to interact with C++ exceptions this way. For example C++ requires that qsort and bsearch propagate the exception thrown by the comparison callback normally

-fexceptions is not needed for this, C++ exceptions will just transparently bubble through C functions without its use.

I don't think I know of any project using -fexceptions… time to google…

Re: C: Simple Defer, Ready to Use

#137
post #41

Earlier quoted context omitted.

No it doesn't; C functions don't set up appropriate registrations with the C++ exception / stack unwinding systems, thus C functions are simply skipped over on the way up towards the nearest exception handler. __attribute__((cleanup(…))) is purely a scope-local mechanism, it has absolutely nothing to do with exceptions.

GCC has comon exception handling across its supported languages. They have exceptions as a C extension that interoperate with C++. Cleanups get called during a stack unwind because they are considered the same as a destructor.

The sibling post to yours has a correct description of the full picture

Re: C: Simple Defer, Ready to Use

#138
post #52

Earlier quoted context omitted.

"If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally." [1] While it's true that it -fexceptions is disabled for C by default, some C libraries need to enable i…

Ah, I forgot about -fexceptions, Thanks. Though I need to point out it's non-default and rarely used, and in particular: > some C libraries need to enable it anyway if they want to interact with C++ exceptions this way. For example C++ requires that qsort and bsearch propagate the exception thrown by the comparison callback normally -fexceptions is not needed for this, C++ exceptions will just transparently bubble th…

glibc allocates in its fallback algorithm within qsort. It has to free the allocation when a C++ exception is thrown in a comparison, unless it wants to leak. I recently filed a ticket for this. They kinda have to compile at least qsort with -fexceptions, unless they use a fully in-place sorting algorithm.

Re: C: Simple Defer, Ready to Use

#139
post #25

The C++ lambda version can be a foot gun: https://godbolt.org/z/Wd66GcrdG , if the return value is a struct, NRVO (named return value optimization) may be applied and the lambda will be called in different order. As for the n3434 proposal, given that the listed implementation experiences are all macro-based, wouldn't it be more easily adopted if proposed as a standard macro like ?

template struct __df_st : T { [[gnu::always_inline]] inline __df_st(T g) : T(g) { // empty } [[gnu::always_inline]] inline ~__df_st() { T::operator()(); } };

#define __DEFER__(V) __df_st const V = [&](void)->void #define defer __DEFER(__COUNTER__) #define __DEFER(N) __DEFER_(N) #define __DEFER_(N) __DEFER__(__DEFER_VARIABLE_ ## N)

#include

struct S { int r; ~S(){} };

(i know hn will mangle this but i won't indent this on mobile...)

people really write cpp like this or is this a intentionally obscure example?

Re: C: Simple Defer, Ready to Use

#140
post #22

Earlier quoted context omitted.

I use a few strategies instead of goto: (1) For simpler cases, wrap in do {} while (0) and break from the loop (2) For multiple cleanups, use same technique combined with checks to see if the cleanup is required. E.g. if (f != null) fclose (f) (3) put the rest of the stuff in another function so that the exit code must run on the way out. In 35 years of coding C/C++, I've literally never resorted to goto. While conve…

How do you handle breaking out of a nested for loop without goto? for (…) { for (…) { if (…) { … goto found; } } } found: This is straightforward with goto and may even be vectorizable. I guess you could move the loop to a separate function or add additional flags to each loop, but neither of these seems like an improvement.

Obviously first two strats don't work, so I would use the third.
Post reply on HN