9 ms·
What is “:-!!” in C code?
- an_account_name 10y agoAh, neat. A version of static_assert for C. What kinds of expressions can it actually evaluate, though?
- viraptor 10y agoAny constant expression. In the kernel it's mostly non-zero flags, sizes of things, etc. See https://github.com/torvalds/linux/search?utf8=%E2%9C%93&q=BUILD_BUG_ON_ZERO https://github.com/torvalds/linux/search?utf8=%E2%9C%93&q=BU... There's also a fun compile time check for arrays: https://github.com/torvalds/linux/blob/1001354ca34179f3db924eb66672442a173147dc/include/linux/compiler-gcc.h#L64 https://github.com/torvalds/linux/blob/1001354ca34179f3db924...
- deleted 10y ago[deleted]
- olalonde 10y agoAnd this is why I hated learning C. You went through a 500 pages C programming book, did all the exercises, had a good grasp of the language but you were still useless because you didn't know anything about those weird macros, Makefiles, automake, gcc flags, etc.
- tedunangst 10y agoThere's nothing particularly weird about this macro, and it has nothing to do with makefiles, automake, gcc flags, etc.
- ajkjk 10y agoIt is insane, though, and should have been replaced with a compiler feature to do static assertions twenty years ago.
- colanderman 10y agoIt was, five years ago. (C11 provides static_assert.) C was probably one of the first widely-used languages to support such a thing, beside Ada and C++.
- tedunangst 10y agoNo, Boost preprocessor is insane.
- ajkjk 10y agoWhy not both?
- viraptor 10y agoI agree that C is complicated, but this one has nothing to do with macros, flags or anything external. All you need to know to understand it is in the language itself. (Similar misunderstanding to the "down to operator" --> https://stackoverflow.com/questions/1642028/what-is-the-name-of-the-operator-in-c https://stackoverflow.com/questions/1642028/what-is-the-name...)
- olalonde 10y agoMaybe the book I read was not that good (Deitel&Deitel) but the section on macros was pretty tiny and I don't think I'd have understood that macro on my own. Anyways, I think C is great, just that most books don't seem to cover the important stuff to work on serious C projects.
- judahmeek 10y agoDeitel&Deitel make some amazing books as far as I'm concerned. They were my source material through college and a very enjoyable introduction to C, C++, and Java.
- colanderman 10y agoThe macro isn't the complicated part in the OP (`e` just gets substituted with whatever the argument is). The definition the macro generates is (for most cases, needlessly) complicated, but that has nothing to do with macros or the preprocessor. The general rules of macros are: 1. Don't use them; prefer static functions. 2. Use them as symbolic constants only. 3. Use parameterized macros only when you must use # or ## (i.e., for code abstraction), and then use them sparingly. 4. If you really insist, wrap every use of the arguments in parentheses, and be careful not to write the name of an argument somewhere where you don't mean it. You'll get pretty far knowing next to nothing about macros (e.g. expansion phases and tokenization rules) by following the above rules.
- anexprogrammer 10y agoI've never understood the feeling that C is complex. Simple syntax, simple rules, a few hidden gotchas for the unwary. "down to operator" = unhelpful use of whitespace. postdecrement x, check if >0 I still find C one of the easiest to pick apart. Obfuscated C entries excepted!
- patmcguire 10y agoOh man, wait until you find out about the Javascript ecosystem.
- olalonde 10y agoFunnily enough, I learned JavaScript about at the same time I learned C (~13 years ago) and at that time, JavaScript was dead simple to learn in comparison. I couldn't imagine myself trying to learn JavaScript today though, I'd probably be banging my head on walls.
- qb45 10y agofunction range_error_on_zero(x) {return Array(-!!x).length}
- kofejnik 10y agoFYI, this is valid js (equivalent to alert(1)): [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
- Immortalin 10y agoThat's why Go is so popular. It's the tooling and user experience that matters.
- hawkice 10y agoOr rather, it's why almost every popular tool is popular. Take Rails for instance. It's just that Go competes with C and boy howdy does the comparison look good to anyone who can make the switch.
- takeda 10y agoI'm not sure that macro in this submission shows that Go is better. Neither Go nor C has static assertions, the macro in questions uses clever techniques to implement one in C, but you probably can't do that in Go. So C is more powerful here. Another example of clever C macro use is implementation of foreach loop (C doesn't have foreach) in linux kernel, here's question about it: http://stackoverflow.com/questions/15754236/how-do-i-use-the-list-for-each-macro-in-list-h-from-the-linux-kernel-properly#15763938 http://stackoverflow.com/questions/15754236/how-do-i-use-the...
- cyphar 10y agoI don't agree that Go's tooling is what makes it popular. Mainly because it's tooling is not very good. All of the vendoring tooling is broken in one way or another, the linters and vet-checkers have questionable advice in some cases, and not to mention that the standard library has so many quirks that come from the fact that Go is trying to be system programming language that hides details about the system from you. [ Disclaimer: I'm a maintainer of runC and have been programming in Go for many years. But that doesn't mean I have to like the language. Give me C any day. ]
- johnfn 10y agoAnd then you look 10 characters to the left of the code and hey, there's the explanation to what it does!
- colanderman 10y agoBad C code is bad C code. There's equally bad JavaScript, Ruby, and Python code too; none of those languages have particularly simple semantics. Moreover, this particular example is due to compatibility issues across the multitude of platforms that Linux supports, necessitating support for versions of C older than any language you might like. Were Linux only ever to be compiled with a C11 compiler, this could be replaced with simply `static_assert(x)`. And speaking as someone who's coded C for 16 years and makes a living doing so: it is rare that I write a macro; my Makefiles are about 5 lines long; I've never touched automake; and the only GCC flags I ever use (and use consistently) are `-std=gnu11 -Wall -Werror -O3`. Heck I wrote a cross-platform NES emulator last month following these rules. There's a lot of bad C out there to find. Don't let that turn you off from writing good C.
- enraged_camel 10y ago>>Bad C code is bad C code. There's equally bad JavaScript, Ruby, and Python code too; none of those languages have particularly simple semantics. The problem is that C is in everything. OK, not literally, but you know what I mean. Bad JavaScript is easy to avoid. You just navigate to another website. Bad C though, not so much. Often times it's in the kernel or somewhere deep like that.
- pjmlp 10y agoAs a side effect of UNIX adoption in the industry. Like it happened with the browser and JavaScript, C got adopted thanks to UNIX. Before UNIX's adoption, many of us had a pleasant coding life using Turbo/Quick/Apple Pascal, Modula-2, Basic compilers.
- noir_lord 10y agoNo idea why you got so badly downvoted, your comment is pretty much spot on, bad C is hard to avoid.
- enraged_camel 10y agoI don't know either. It happens sometimes. I think it's just the bandwagon effect, and depends on the initial votes and their timing.
- simias 10y agoWhile this construct looks pretty weird if you decompose it element by element using the rules of the language it becomes rather clear IMO. The most arcane feature here is probably the bitfield syntax that you might not encounter very often in the wild. The problem with C IMO is that the compilers are very permissive by default and it's easy to trigger an undefined behaviour with seemingly harmless code if you're not careful. Things like promotion rules make it difficult to guess at a glance how the code is going to behave if you don't have a very good understanding of these (rather quircky) rules. There's also the whole mess of the pointer vs. array distinction which sometimes matter and sometimes doesn't etc... By comparison these BUILD_BUG_ON macros are relatively straightforward IMO. The naming is a bit misleading unfortunately but at least it's in full CAPS so you know it's a macro...
- deleted 10y ago[deleted]
- comex 10y agoNote that C11 has a more friendly static assertion feature: _Static_assert(condition, "error message if condition evaluates to false"); (You can also use "static_assert" as an alias for the ugly keyword after including <assert.h>.)
- 0xFFC 10y agoI wander what kernel developers thinking about migrating toward C11.
- CapacitorSet 10y agoI think there's a better chance for a static_assert proposal in C, especially since Torvalds isn't particularly fond of C++. Edit: whoops, apparently static_assert is in C11 as well as in C++11. Ignore this comment.
- zodiac 10y agoC11 isn't C++
- olliej 10y agoIt's a person misreading syntax :-/
- deleted 10y ago[deleted]
- jzymbaluk 10y agoEvery time I feel pretty good about my knowledge of C, something like this comes along and reminds me I don't know anything at all.
- Mindless2112 10y agoThat code seems needlessly arcane. You can get the same results without resorting to anonymous bitfields: #define BUILD_BUG_ON_ZERO(e) (sizeof(char[(e) ? -1 : 0])) which, when it fails, results in error: size of unnamed array is negative which is no worse than the provided code which results in error: negative width in bit-field '<anonymous>' It's worth noting that declaring an array with 0 elements is not allowed in C99. However, using a struct with no named members has undefined behavior in C99 [1]. [1] http://stackoverflow.com/a/12918937/959866 http://stackoverflow.com/a/12918937/959866 Edit: You can get around having 0 elements by using #define BUILD_BUG_ON_ZERO(e) (sizeof(char[(e) ? -1 : 1]) - 1) but you're starting to lose clarity again.
- peterdn 10y agoIn some compilers due to C99 variable length arrays [1], your macro compiles happily if passed a value that is not a compile-time constant. For example, this compiles but segfaults at runtime (GCC 4.9.2): int main(int argc, char * argv[]) { return (sizeof(char[(argc) ? -1 : 1]) - 1); } [1] https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
- Mindless2112 10y agoAh, good point. One more reason for me to hate VLAs. ;) The negative-length array trick is used in the Linux kernel source code [1]. I expect it's compiled with -Wvla though. [1] https://github.com/torvalds/linux/blob/v4.5/arch/x86/boot/boot.h#L32 https://github.com/torvalds/linux/blob/v4.5/arch/x86/boot/bo...
- mkesper 10y agoRust discussion of a similar feature: https://github.com/rust-lang/rust/issues/6676 https://github.com/rust-lang/rust/issues/6676
- lordnacho 10y agoHere's another one. http://stackoverflow.com/questions/1642028/what-is-the-name-of-the-operator-in-c http://stackoverflow.com/questions/1642028/what-is-the-name-... int main() { int x = 10; while (x --> 0) // x goes to 0 { printf("%d ", x); } }
- thanatropism 10y agoSemi related to the "is C ugly" debate. I know Fortran 90 and use it for some simulations -- since it has a matrix syntax it's not that hard to write changing matlab code. But I know Fortran is going where the wild roses grow, and wonder if I should spend the time to learn C for high-dimensional numerics.
- qwertyuiop924 10y agonah, FORTRAN is alive and well in high-performance mathematics. I wouldn't worry.
- muyuu 10y agoThe question adds confusion to it, should have put the whole macro to give it context.
- austincheney 10y agoThe next time developers cry about JavaScript's incompetence because of potential hacky type coercion stupidity I will shove this in their face.
- hohenheim 10y agoAnd why would that justify JS issues? If anything, it shows we have ignored the history and we are repeating it.