4 ms·
GCC and Clang specific, as said in the readme page. I know, apply.h is ugly, but I did not want to lose too much time on that (and it was easy to dump these li
by Snaipe 12y ago
GCC and Clang specific, as said in the readme page.
I know, apply.h is ugly, but I did not want to lose too much time on that (and it was easy to dump these lines from a shell command), as it is only used for an optional macro.
When the recursion limit is hit, every parameter after that is ignored, and I doubt someone will ever use a struct with 64 members needing destruction, considering of course they would use this, and use the completely optional "DESTRUCTOR" macro helper.
But yes, I get it, I'll probably find the time to implement some kind of recursion based off OBSTRUCT/DEFER that we often see on stackoverflow.
- minthd 12y agoThis looks great. From the examples, it seems that it is fully compatible with standard pointers with no need of casting. Is it true ? If so, it could work well in simplifying development with embedded development libraries, say like the mbed.
- Snaipe 12y agoYup, these are just pointers, usage is still the same, and no cast/special functions are needed to manipulate them.
- TheLoneWolfling 12y agoWell... you cannot call free on them, unless I'm mistaken. But other than that it's as normal. (This could be a problem if you want to call library code that frees a supplied pointer)
- Snaipe 12y agoAh, yes, good point. Great care should be taken for these cases to not happen.
- kazinator 12y agoYou can make smart pointers which are not specific to a GNU language. Here is how: doh, use C++. Let's see, ISO C++ portable smart pointers? Or GNU/LLVM C smart pointers? If all you want is a C dialect, with smart pointers (and nothing else from C++), you can easily program that way. So here is an idea: in a similar vein, you can make your scheme work with C or C++. You then have code which can be compiled as standard C++, and has smart pointers. Or, it can be compiled using the LLVM/GNU dialect of C and it can have smart pointers. (Okay, so what is the benefit, then? Just that someone can build such a program without a full toolchain that includes a C++ compiler: the program is buildable with a more bare-bones toolchain. There are some added benefits in that you can validate the code on more compilers!) From the point of view of the implementation of this, it could be great. Add a few #ifdef __cplusplus in there and see if you can target C++. You then have more ways to test things.
- __david__ 12y ago> If all you want is a C dialect, with smart pointers (and nothing else from C++), you can easily program that way. Really? Which dialect of c++ lets me use c99 structure initializers? C++ is no longer a superset of C.
- kazinator 12y agoAnyway, this smart pointer interface doesn't have to dictate any such a dialect to its users; it can just have C++ as a target. It was just a thought. When I work in a restricted dialect of C that is portable to C++ compilers, I have better type safety: safer treatment of void *, string literals that are const-qualified, type-safe enumerations, and safer casting operators (reinterpret_cast, const_cast, static_cast) which I can hide behind macros that work in C or C++. On the other hand, I don't have C99 designated initializers. It would be great to have both! If I had some static data that would so greatly benefit from these initializers that I cannot do without them, I might put that into a separate module that is compiled as C99. Not terribly convenient if you just want to throw a handful of static functions into an operations structure, though or whatever. There are solutions for better initialization available when you're working in C90. For each structure that is instantiated somewhere with an initializer, you can write an initializer macro instead. The macro is close to the structure definition and is maintained together. If you need a few different ways of initializing the same aggregate, then several macros can be provided that have different argument lists and different defaulting. When a new member is added (that isn't defaulted), the macros get a new argument. Either way, their expansions are carefully edited to initialize that member. The macro bodies of such initializer macros provide a complete initializer, covering every member explicitly. If the addition of a new member results in a new macro argument, the existing macro calls then do not compile; they have to be maintained. (Whereas naked initializers just keep compiling and become incorrect when structure members shuffle around: the nasty problem we want to avoid.) Ultimately this functional approach is more disciplined and safer than designated initializers. From a safety point of view, designated initializers only solve the problem of the wrong initial value going to the wrong aggregate member (that by chance has a suitable type to accept that initializer without a diagnostic). Functional initializers take a more complete approach of specifying the initialization in terms of constructor-like parameters, which are required, with the possibility of defaulting other elements to values other than zero. The one thing designated initializers do which cannot be beaten, is that you can declare a million element array and initialize element [999999] to 42, statically. This may be a bad idea; some linkage models may actually implement that by adding one million words of initialized data to your executable image. Whereas if you leave it uninitialized, and stick in the 42 at run-time, the whole object is in the "BSS" section.