14 ms·
The Preprocessor Iceberg Meme
- hwers 4y agoAnyone know what SIMD means at the bottom layer is here? I know what SIMD is I mean in the context of the preprocessor (and being the worst offender apparently).
- pavlov 4y agoYou can click on each item for an explanation.
- gpderetta 4y agoIt is not obvious, but the entries are clickable! It [0] is apparently a technique for speeding up processing of preprocessor lists. edit: it is basically loop unrolling. [0] https://jadlevesque.github.io/PPMP-Iceberg/explanations#single-instructioncontinuation-multiple-data https://jadlevesque.github.io/PPMP-Iceberg/explanations#sing...
- camel-cdr 4y agoSorry, I misread your comment as clickbait instead of clickable. ~~I can see how others are somewhat clickbait, but this is literally single instruction/continuation multiple data. It uses a single step in the continuation mechanism to compute on multiple elements of data to speed up the computation.~~
- gpderetta 4y agoNo worries, I probably misread your comment too :). I thought you were asking what SIMD/SCMD is in this context, but as the submitter you probably already did, and already knew that the links were clickable. BTW: I don't think the titles of each entry are particularly clickbait-y.
- zabzonk 4y agoI started but couldn't finish. For example __FILE__ (and __LINE__ and similar) certainly can be used in user-written macros, but they evaluate to the file/line they appear at in the macro source, not at the line the macro is invoked.
- elteto 4y agoThis is not correct. They evaluate at the point where they are expanded. I’ve used them countless of times to implement “log” and “trace” macros that show file/line.
- zabzonk 4y agoI have used them countless timers myself, but not within another macro Edit: Sorry I am on multiple drugs at the moment for a severe fracture - I'm a bit confused, nurse has just been. I will shut up now. To prove I am not completely out of it (though wrong), here's one I wrote a lot earlier: https://latedev.wordpress.com/2012/08/09/c-debug-macros/ https://latedev.wordpress.com/2012/08/09/c-debug-macros/
- gpderetta 4y agomost commonly they are typically used in the definition of the assert macro. For example: https://github.com/lattera/glibc/blob/master/assert/assert.h https://github.com/lattera/glibc/blob/master/assert/assert.h .
- camel-cdr 4y ago
- camel-cdr 4y agoSince some people missed this, every entry is a clickable link.
- dosshell 4y agoexplanations: https://jadlevesque.github.io/PPMP-Iceberg/explanations https://jadlevesque.github.io/PPMP-Iceberg/explanations
- gpderetta 4y agoThis is awesome! The C/C++ preprocessor is probably the esoteric programming language that see the most real world use. Or would that be C++ template metaprogramming...?
- MauranKilom 4y agoCan someone explain what #if static_cast<bool>(-1) is about? My thoughts were "that's just #if true, no?", then "wait, static_cast is not part of the preprocessor, that can't work" to "wtf, it actually compiles"... Edit: As people point out, you can click on it to get context. And yeah, that one is an oof.
- adzm 4y ago> The #if statement replaces, after macro expansion, every remaining identifier with the pp-number 0. So #if static_cast<bool>(-1) is equivalent to #if 0<0>(-1), #if 0 > -1, and #if 1. Wow, I have no idea why this would ever be done.
- jcelerier 4y agowell it's the consequence of #if SOME_STUFF evaluating to 0 if SOME_STUFF isn't defined
- kazinator 4y ago> I have no idea why this would ever be done. You'd never literally write #if static_cast<bool>(-1) but it could be the result of a macro expansion.
- sudosysgen 4y agoBecause the preprocessor doesn't know what static_cast is, so in an if it just evaluates to false as do any values that haven't been defined.
- kazinator 4y agoI suspect the point is that the preprocessor language expression syntax that is out of whack with the host languages it is integrated into. If you hoist an expression of the language proper into a preprocessing directive, you may get gibberish. This could happen by accident, particularly through layers of macros: Say you have: #if SOME_MACRO(ARG) originally, this expands to an constant expression in which everything is an integer; then someone edits the macro. Things may still compile, but the expression is gibberish, not doing what it looks like it's doing. The macro could be used in non-preprocessing contexts: int x = SOME_MACRO(X); if (SOME_MACRO(Y)) ... so that programmer might have a good reason for editing it; just they didn't notice it's also used in an #if directive.
- sk0g 4y agoUnrelated, but yesterday I found out you can have two bools in C++ that are both true but do not equal each other, by reinterpret casting them from (u)ints. I think this was for the standard bool type too... Now I'm questioning the most basic of things.
- pjmlp 4y agoIt boils down to C compatiblity, every non zero numeric value is true, that language where good developers make no errors.
- sk0g 4y agoI know that's the case for ints, but in this case [0] the int was cast to a boolean, which I thought would ensure comparisons would perform as expected, but no such luck. [0] https://www.onlinegdb.com/tfHPZ_FOfY https://www.onlinegdb.com/tfHPZ_FOfY
- gpderetta 4y agoYou are not casting an int to a bool (which would indeed do the right thing) but casting a pointer to int to a pointer to bool which violates strict aliasing.
- sk0g 4y agoAh fair, thanks for pointing it out! Wasn't my issue, just the minimal reproduction of behaviour that happened over a few external modules, causing this issue.
- jstimpfle 4y agoThis is not strict aliasing as far as I understand. Strict aliasing is about inference of distinctness of pointers. The case here is that an invalidly typed pointer is created (a bool pointer pointing to where there is no bool). Not sure what this situation is called in standardese.
- userbinator 4y agoRelatedly, this article is claimed to be a description of the algorithm that the C standard intended; it is surprisingly succinct: https://news.ycombinator.com/item?id=22444447 https://news.ycombinator.com/item?id=22444447
- svnpenn 4y agoand... this is why I prefer Go. No macros.
- isatty 4y agoGo has even uglier half supported things like #embed.
- camel-cdr 4y ago#embed coming to c distributions near you in 2023 [0] [0] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm
- svnpenn 4y agoSeems fine to me: https://godocs.io/embed https://godocs.io/embed Difference is it's just data, not executable code. I don't understand why people need macros, when functions exist.
- pjmlp 4y ago//go:generate
- stelonix 4y agoIt's a huge reminder C++ is missing a proper, hygienic, macro system. Too many things that are a pain to do in C++ would be easy with a real macro language. I have hope we'll get it sometime this decade, seeing all the work on the language since C++11 still happening more than 10 years later. It's worth nothing that a macro system plus basic reflection is where the real power of macros lies at.
- otabdeveloper4 4y ago> It's a huge reminder C++ is missing a proper, hygienic, macro system. Templates, man.
- smitty1e 4y agoI'm standing by for the announcement that some caffeine-addled Boost metaprogramming madman has implemented the Rust borrow checker as a C++ template, or at least thinks that he may have, when the compilation completes sometime in the 2030s.
- gpderetta 4y agoIt is not like I didn't try...
- steveklabnik 4y agohttps://docs.google.com/document/d/e/2PACX-1vSt2VB1zQAJ6JDMaIA9PlmEgBxz2K5Tx6w2JqJNeYCy0gU4aoubdTxlENSKNSrQ2TXqPWcuwtXe6PlO/pub https://docs.google.com/document/d/e/2PACX-1vSt2VB1zQAJ6JDMa...
- smitty1e 4y agoIt's not clear how much boost.org magic they used. Failing that, a GCC extension could be needful. From the ref: --- Conclusion We attempted to represent ownership and borrowing through the C++ type system, however the language does not lend itself to this. Thus memory safety in C++ would need to be achieved through runtime checks. Example code #include <type_traits> #include <utility> #include <assert.h> #include <stddef.h>
- kazinator 4y agoI wrote a useful extension to the C preprocessor for GCC, and submitted it to the gcc-patches mailing list in April. This went unnoticed, as have my subsequent pings since. I'm planning to ping once a month from now on until the rest of 2022, and then switch to quarterly. https://gcc.gnu.org/pipermail/gcc-patches/2022-April/593473.html https://gcc.gnu.org/pipermail/gcc-patches/2022-April/593473.... __EXP_COUNTER__ gives a macro expansion to a numeric value which uniquely enumerates that expansion. The sister macro __UEXP_COUNTER__ allows a macro expansion to access the parent's value: if a macro is being expanded in the body of another macro, one level up, it provides the __EXP_COUNTER__ value of that parent macro. This feature solves the problem of producing unique names in a macro. (Unique within a translation unit.) The __LINE__ symbol gets abused for this. The problem is that it's not unique. A macro can be called two or more times in the same line of code. Moreover, the same line number like 42 can occur multiple times in the same translation unit due to #include; a line number is not unique within a translation unit. __COUNTER__ is next to useless because on each access, its value changes. It's useful in a situation in which a name is needed syntactically, and has to be unique, but is otherwise never referenced: just mentioned once and that's it. Multiple references to __EXP_COUNTER__ in the same macro expansion context produce the same value.
- gpderetta 4y agoI'm probably missing something, but can't you use counter to generate a unique name once and then forward to to another macro so that it can be used multiple times?
- kazinator 4y agoPossibly. Whereas definitions are lazily evaluated, so that if we have: #define COUNT __COUNTER__ each occurrence of COUNT behaves like an invocation of __COUNTER__. But, this is not true of parameters because they get expanded before substitution. $ gcc -E - #define MAC(PARAM) PARAM PARAM PARAM MAC(__COUNTER__) # 1 "<stdin>" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "<stdin>" 0 0 0 Thus perhaps you may be able to get something like __EXP_COUNTER__ by splitting your macros into interface and implementation: #define MAC_IMPL(A, B, EXP_COUNTER) #define MAC(A, B) MAC_IMPL(A, B, __COUNTER__) I'm guessing this is what you mean by forwarding. This could be a pretty major inconvenience, if you have to do it in the middle of a situation that is already stuffed with preprocessing contortions. Like say you had to define 32 macros that are similar to each other, for whatever reason, and you want this hack: now you have 64.
- tasty_freeze 4y agoThis one has bit me twice in the past 35 years. I have some program I'm working on, doing the usual edit/compile/run/debug cycle. At some point I decide to compare two versions of some section of code, so I write out temporary files of the old section named "old" and the new section named "new". Then compiles start failing, but oddly it is a file that I haven't edited recently. The issue is that some code (not necessarily even mine) has an "#include <new>" and it is picking up my temporary file named "new".
- gpderetta 4y agoOne of the most odd issues I have encountered was a test case that would fail if one random log line was deleted (which would normally means UB or timing issues) but, wildly, not when the log line was commented out. Turns out it was interaction between the use of __LINE__ in a macro to generate unique identifiers and a violation of the One Definition Rule.
- hermitdev 4y agoHeh. If I had a nickel for every time I shot myself in the foot over the years by dropping a temporary file named "test.py" somewhere... I'd don't know about rich, but I'd probably at least be able to buy myself a coffee.
- WalterBright 4y agoMacro systems inevitably wind up being used to create a specialized undocumented language that nobody but its creator understands. I know how enticing they are, I designed and implemented one myself for the ABEL programming language. I used lots of clever C macros in my C programming, and was proud of them. But, eventually, I removed all the macro usage, and quite preferred the resulting code. It was cleaner and easier to read. It's not just C macros. It's the same for assembler macros. I've heard from others it's the same for other languages that rely on macros. Essentially, macros are a cheap way to add power to a language. A better way is to add proper metaprogramming features. This is the route we chose to go with D, and it is satisfyingly successful. Macros - just say no.
- vitiral 4y agowhat if instead of the macros being a side language, they _are_ the language? (github.com/civboot/fngi)
- arka2147483647 4y agoI have seen this kind of ”flip-flop” behaviour people have with macros a few times. First you go all in, burn yourself, and then go to the other extreme. Personally, i think macros are a good way to automate some common tasks, but you have to be carefull to keep them short. Also it is a good idea to prune macros periodically to remove what you dont need. In Cpp, If you find yourself choosing weather to use a macro or a template; Choose the one which is more terse! Also macros will always inline in debug while templates will generate functions in debug builds, without optimizations. This may be an important performance consideration at times.
- WalterBright 4y agoD has an "always inline" annotation for functions, so they'll be inlined even in debug builds if so desired. Using a symbolic debugger with macros is just another facet of the slow moving disaster of macro usage.
- stingraycharles 4y agoI can hear the sound of a thousand LISP devs hurting in parens reading this comment lol. Macros, as with most things (including even goto!) have their place, the problem is when they’re abused. But to say they’re never useful ever and you should instead always rely on language features is not something I agree with, and could even lead to language bloat if you need a full fledged feature for every little thing which would be trivially solved with a macro.
- rwmj 4y agoRecently started hiding "... do" and "while (0);..." in macros to write nicely bracketed start and end C macros eg this set for generating HTML: https://github.com/libguestfs/libguestfs-common/blob/master/utils/libxml2-writer-macros.h https://github.com/libguestfs/libguestfs-common/blob/master/... You can write: start_element ("memory") { attribute ("unit", "MiB"); string_format ("%d", g->memsize); } end_element (); to generate <memory unit="MiB">1024</memory>
- ttoinou 4y agoWhy do you need to start with while (0); ?
- webstrand 4y agoThat's pretty cool. It's been a while since I've done C, but couldn't you use a `for` loop instead of a while and perform any necessary cleanup in the "update" section? i.e. https://gcc.godbolt.org/z/jq84jondh https://gcc.godbolt.org/z/jq84jondh (The condition is optimized away by the big three: msvc, clang, and gcc)
- billforsternz 4y agoLooks good. I wonder why this trick is invariably implemented with "do {" and "} while (0)" and never with "if(1) {" and "} else" ?
- sebastialonso 4y agoLove this iceberg with explas for PLs. Does anyone know another one?
- 7373737373 4y agohttps://icebergcharts.com/i/Python_Syntax https://icebergcharts.com/i/Python_Syntax
- fouronnes3 4y agoI made a general one about C++ some time ago: https://fouronnes.github.io/cppiceberg/ https://fouronnes.github.io/cppiceberg/
- tialaramex 4y ago"C++0x concepts were rust traits" was an interesting read, leading me to look at P2279, and then at P2437 which may end up in C++ 26. Thanks.
- Dav3xor 4y agoThis illustration is missing a layer. Buried down in the silt, under the abyssal plane at the bottom of the ocean.. Ken Thompson.
- raldi 4y agoEven with the explanations, I still don’t understand “no argument means one argument”
- MichaelMoser123 4y agoi don't know which is worse: pre-processor abuse in C land or object oriented design abuse in C++ land, both can lead to code that is quite hard to maintain... (i know that you can have pre-processor abuse in C++ too, but that's not common practice)