8 ms·
A Defer Statement for C
- eqvinox 7y agoSounds like you're trying to emulate the "cleanup" GCC variable attribute: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attribute... Example use: https://github.com/FRRouting/frr/blob/master/lib/frr_pthread.h#L218-L264 https://github.com/FRRouting/frr/blob/master/lib/frr_pthread... (FRR requires a GCC/clang compatible compiler, so no fallback/workaround.)
- CameronNemo 7y agoLXC also uses this attribute.
- loeg 7y agoGCC attribute cleanup is so much harder to misuse than some hodgepodge macro construction like this. If you're a C developer, it is by far the superior option. Clang supports it, of course.
- rwmj 7y agoIt's also used in several important big Linux programs so it's unlikely to be going away. There have been efforts to get the mechanism added to the next C standard too.
- loeg 7y agoRe: going away — has GCC ever removed any relatively common attribute in the past? They basically don't ever, to my knowledge. They haven't removed nested functions, for example, which would probably be a good idea. (To your point, though: important Linux programs like GRUB use nested functions.)
- ill0gicity 7y agoThis is one I put together a while back for gcc and clang: https://github.com/jeffwalter/defer/ https://github.com/jeffwalter/defer/. There's no limit to the number of defers you can have. At least not one I've run into.
- earenndil 7y agoMy version isn't as dependent on nonstandard extensions.
- lxe 7y agoLooks like you also have to use a custom return (`Return`) which is error-prone.
- cryptonector 7y agoYou can define the macro as `return` -- it won't cause infinite recursion in the C pre-processor, but you do have to either use the `Deferral` macro in every function, or `#undef return` to do a plain return. Try it. I just did, and it works.
- convolvatron 7y agoi have done something similar by using the ptrace hooks..you can ask the compiler to insert the calls, but link in your own functions instead.
- cryptonector 7y agoYou could use a Duff's device instead of computed labels, then you'd have a portable implementation.
- electrum 7y agoThat same technique is used by https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
- cryptonector 7y agoYes, quite! I mentioned that and async.h in issue #1. I also opened a PR with a Duff's device version.
- waynecochran 7y agoHow does this compare to using RAII in C++ in terms of generated code?
- MaxBarraclough 7y agoAs I mentioned in another comment, it seems almost identical to Boost.ScopeExit, [0] but with the special restriction that it causes statements to run at the point a function returns. From the article: it does not care about lexical scopes. edit Looking at the implementation, it seems to use setjmp/longjmp on some platforms. Nasty. I believe Boost.ScopeExit does some macro trickery to leverage C++'s RAII, which isn't so bad. [0] https://www.boost.org/doc/libs/1_72_0/libs/scope_exit/doc/html/index.html https://www.boost.org/doc/libs/1_72_0/libs/scope_exit/doc/ht...
- cryptonector 7y agoIt's almost certainly strictly more code, as this code maintains an array at run-time. You can use godbolt to see it if you like.
- MaxBarraclough 7y agoFor the C++ equivalent see Boost.ScopeExit https://www.boost.org/doc/libs/1_72_0/libs/scope_exit/doc/html/index.html https://www.boost.org/doc/libs/1_72_0/libs/scope_exit/doc/ht...
- mhh__ 7y agoAnd for that concept generalised see scope statements in D
- maxlybbert 7y agoBased on ScopeGuard ( https://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758 https://www.drdobbs.com/cpp/generic-change-the-way-you-write... ).
- lyricaljoke 7y agoOr, arguably, the C++ equivalent is just the destructor. 'Defer' and 'ScopeExit' are interesting, but I'm not sure if I see the advantage over widely understood first-class language features. If you don't want to write a class just to get cleanup logic at scope exit, consider using std::unique_ptr with a custom deleter -- this construct is for managing resources in a general sense, not necessarily just memory allocation.
- MaxBarraclough 7y ago> arguably, the C++ equivalent is just the destructor You'd have to define an empty class with a destructor, then instantiate the class at the appropriate place in your code. The point of Boost.ScopeExit is to handle that boilerplate for you. > I'm not sure if I see the advantage over widely understood first-class language features The advantage is simply reduced boilerplate. You're right that it's 'less standard' and more likely to baffle the reader, if they're not already familiar with ScopeExit. > consider using std::unique_ptr with a custom deleter -- this construct is for managing resources in a general sense, not necessarily just memory allocation This strikes me as hijacking a memory-management facility, using it for a different purpose than its intent. That's bad for readability. I'd prefer either ScopeExit or the dummy object pattern I described.
- devit 7y agoMoving to C++ seems wiser than using a dubious hack like this.
- Animats 7y agoAgreed. "Defer" in Go isn't a great idea anyway. It's more what they were forced to, given a GC language without actions at scope exit. (Callbacks from the garbage collector on deallocation are even worse. That way lies locking problems and "re-animation", a nightmare in Managed C++. One of the cleaner solutions to scope-based cleanup is the "with" clause in Python, which is based on "with" constructs in Common LISP. Only thing I've seen where exceptions in a destructor work right.)
- dnautics 7y agoDefer and errdefer in zig are pretty awesome, so I'm not convinced c couldn't use it, but zig has a very different error return model from C, and I tend to disapprove of hacky solutions.
- earenndil 7y agoI wrote on reddit[1] about why I prefer this over c++: > It's not a technical problem, but a social problem. Yes, I would definitely prefer the c++ RAII (and refcounts would be nice too). If you say 'my project is in c++', that sends a certain message to prospective contributors, about what your priorities and ideals are. It can attract certain kinds of contributors and discourage others. Then you have the problem of how to define your subset of c++. It's easy to say 'no exceptions, no RTTI, no STL'. But there are subtler things. As you mention, templates are occasionally useful. But sometimes they're completely superfluous. Do you allow virtual functions? Multiple inheritance? The answer is almost invariably 'maybe'; you have to exercise taste. I can do that by myself, for my own project. But if I want to be able to accept contributions from others, I need a clearer set of contribution guidelines than 'wherever my whimsy takes me', and for such a purpose 'whatever the c compiler accepts' is the best I can do. > Also, tcc is about 10x faster than gcc and clang, which makes development a joy. 1: https://www.reddit.com/r/programming/comments/f4gb6n/i_made_defer_for_c/fhqo14q/ https://www.reddit.com/r/programming/comments/f4gb6n/i_made_...
- deleted 7y ago[deleted]
- adamrezich 7y agocool hack! idk about its usefulness in production but cool nonetheless
- earenndil 7y agoAuthor of the library here; AMA.
- rwmj 7y agoWhy not use __attribute__((cleanup))? It's widely used in real code (eg. systemd has been using it for years) and there's effort going on to get the mechanism standardized in the next C standard.
- Kipters 7y agoHow is support across compilers? Do clang and MSVC support it?
- rwmj 7y agoGCC and Clang yes. Do people even use MSVC to compile C (not C++) code? Last I heard it was years behind on the C standards. In any case few in the Linux community care too much about closed source compilers. Lack of MSVC support for cleanups would be amongst the least of your problems if you were trying to use it to compile systemd or libvirt.
- loeg 7y agoDoes MSVC support C99 yet? Much less C11 or a future C2x? Their priority has always been C++ and for some time their stance on C was basically "I guess we're willing to compile the subset of C that is valid C++."
- pwdisswordfish2 7y agoWhere's the effort? I happen to follow WG14 proposals closely, but I haven't seen this particular one discussed prominently or incorporated into the latest working draft. I don't even remember a single paper with this feature submitted to WG14 for consideration.
- earenndil 7y agoYou need to use nested functions if you want to have nontrivial behaviour in a cleanup, and nested functions are awful in c.
- zvrba 7y agoUses globals. Not thread-safe in any way.
- CGamesPlay 7y agoI don't think it actually does. Per the example, the `Deferral` macro instantiates local variables which are used to do the unwinding.
- zvrba 7y agoOh, you're right. I missed \ at the end of definition of Deferral macro.
- rkeene2 7y agoSemi-related, I built one for Tcl [0]. [0] https://chiselapp.com/user/rkeene/repository/tcl-defer/ https://chiselapp.com/user/rkeene/repository/tcl-defer/