Braiding the spaghetti: implementing defer in the preprocessor
The blog post discusses a "defer" mechanism in C for improved resource management, simplifying cleanup code execution, enhancing readability, and addressing limitations in handling return types and control statements.
Read original articleThe blog post discusses the implementation of a "defer" mechanism in the C programming language, aimed at improving resource management and cleanup in code. The traditional approach often leads to complex and error-prone patterns, such as using `goto` statements for cleanup, which can make code difficult to read and maintain. The proposed defer feature allows developers to specify cleanup actions that will be executed at the end of a compound statement, thus keeping the cleanup code close to where resources are allocated. The implementation leverages preprocessor extensions to manage the complexity of label generation and control flow, allowing for a more straightforward coding style. The author notes that while the current implementation in the eĿlipsis preprocessor has some limitations, such as handling return types and certain control statements, it represents a significant step towards cleaner and more maintainable C code. The blog emphasizes that modern compilers can handle the complexity introduced by the preprocessor, making the code efficient while providing valuable feedback for static analysis.
- The "defer" mechanism simplifies resource management in C by executing cleanup code at the end of a compound statement.
- Traditional cleanup patterns using `goto` can lead to complex and error-prone code.
- The implementation uses preprocessor extensions to manage label generation and control flow.
- Current limitations include handling non-void return types and certain control statements.
- The approach aims to enhance code readability and maintainability while remaining efficient for compilers.
Related
Weekend projects: getting silly with C
The C programming language's simplicity and expressiveness, despite quirks, influence other languages. Unconventional code structures showcase creativity and flexibility, promoting unique coding practices. Subscription for related content is encouraged.
Some Tricks from the Scrapscript Compiler
The Scrapscript compiler implements optimization tricks like immediate objects, small strings, and variants for better performance. It introduces immediate variants and const heap to enhance efficiency without complexity, seeking suggestions for future improvements.
Malloc() and free() are a bad API (2022)
The post delves into malloc() and free() limitations in C, proposing a new interface with allocate(), deallocate(), and try_expand(). It discusses C++ improvements and emphasizes the significance of a robust API.
Safer code in C++ with lifetime bounds
Daniel Lemire's blog emphasizes using lifetime bounds in C++ to improve code safety and performance, highlighting the role of std::string_view in avoiding unnecessary copies and preventing dangling references.
C2y Proposal: Essential Effects for C
The proposal "Essential Effects for C" by Alex Celeste aims to enhance C with a type and effect system for better side effect management, categorizing effects into Local, Persistent, and Control groups.
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attribute...
This is the kind of things better done in the compiler, I implemented the n3199 variant of defer[1], along with [[gnu::cleanup]], in a small C compiler with about 200 LOC by extending the VLA de-allocation algorithm, the process is archived at [2].
[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3199.htm [2] https://github.com/fuhsnn/slimcc-defer/commits/
I would prefer a directly scoped syntax similar for a for statement, something like
defer (void * p = malloc(17); free(p)) {
...
}
This gets more cumbersome as you have more such scopes in a function, but it gives a sane bounding. You can sort of do this now with a properly constructed for loop so that it cleans up on regular exit from the loop, but it can't handle exception exits (returns, breaks, and god forbid goto or longjmp).The only annoying part is needing to use "defer_return" and such instead of the proper keywords.
Unlike most defer implementations for C this doesn't need a function-scope fixed sized block, it's all properly scoped, the switch effectively models a state machine. Similar tricks can be used to implement yield and such.
void foo() {
char *p = malloc(...);
defer free(p);
...
{
FILE *p = fopen(...);
defer fclose(p);
...
}
return;
}
Would it run both deferred statements, each with the correct argument?- straightup forgetting to free shit - writing horrible to read code making it impossible to do cleanup or track allocations
why try to make c into c++ or rust? those languages already exist.
Related
Weekend projects: getting silly with C
The C programming language's simplicity and expressiveness, despite quirks, influence other languages. Unconventional code structures showcase creativity and flexibility, promoting unique coding practices. Subscription for related content is encouraged.
Some Tricks from the Scrapscript Compiler
The Scrapscript compiler implements optimization tricks like immediate objects, small strings, and variants for better performance. It introduces immediate variants and const heap to enhance efficiency without complexity, seeking suggestions for future improvements.
Malloc() and free() are a bad API (2022)
The post delves into malloc() and free() limitations in C, proposing a new interface with allocate(), deallocate(), and try_expand(). It discusses C++ improvements and emphasizes the significance of a robust API.
Safer code in C++ with lifetime bounds
Daniel Lemire's blog emphasizes using lifetime bounds in C++ to improve code safety and performance, highlighting the role of std::string_view in avoiding unnecessary copies and preventing dangling references.
C2y Proposal: Essential Effects for C
The proposal "Essential Effects for C" by Alex Celeste aims to enhance C with a type and effect system for better side effect management, categorizing effects into Local, Persistent, and Control groups.