Having fun abusing the C language
faehnri.ch
faehnri.ch
typedef int myint;
int typedef myint;
The only difference here compared to a normal declaration is that the name "myint" defines a type and not an "object" as per the standard.It was over 25 years ago that I first came across the C language FAQ from the Usenet group comp.lang.c and it explained the "commutative property" of array subscripts. (Online version here: http://c-faq.com/aryptr/joke.html). Another similar stackoverflow Q&A has also been done: http://stackoverflow.com/questions/381542/with-c-arrays-why-...
Over the last 2 decades, I have never needed the knowledge that the C language lets you put a number outside the brackets instead of inside it. Other than deciphering obfuscated C puzzles, I've never run across any real world source code that took advantage of that syntactic quirk. So yes, I did learn that trivia about array subscripts -- but it was useless knowledge.
#define count(array) (sizeof(array) / sizeof(0[array]))
...will conveniently cause a compile error if you accidentally pass in a std::vector instead of an array.Also, typechecking macro arguments with ?: is quite interesting, check it out. :-)
welcome to C programming!
It's hard for me to pick a favorite, but perhaps one of the most memorable is 2004-gavare: http://www.ioccc.org/2004/gavare.c. This little gem implements a fairly sophisticated ray tracer using no C keywords or preprocessor directives at all: no "int", "char", "if", "return", "#define", etc. I learned a great deal about computer graphics (and, yes, C programming) from reverse-engineering that program.
#include <stdio.h>
int main() {
if ('|' != '??!') {
printf("ok");
}
else {
printf("oops");
}
return 0;
}
[0] https://en.wikipedia.org/wiki/Digraphs_and_trigraphs #define struct union #define TRUE FALSE
or the even more pernicious: #define 1 0Also, I'm not sure how you think it's particularly obvious (as opposed to any other #define trick). It does only work if the project isn't warning-safe, as there are various ways this'll trigger ugly warnings (eg. using designated initializer syntax causes re-initialization warnings), but even then the warnings don't tend to actually tell you it's a union all of a sudden.
If you have others, I'd like to hear them.
#define if while
#define else while(!true){}
That should be interesting.- Remember the order of includes change how they are applied. Have a #define that changes something in a .h that's included in some files but not in others
- (Depending on the software) redefine rand() to be almost predictable or with a short loop
Might have been the Lua Programming Gems book...
#define NULL rand() #ifdef NULL
#undef NULL
#endif
#define NULL (void*)((size_t)!rand())
* Doesn't trigger errors
* Will almost always return 0 (every time rand() returns a non-0 value), so code will almost never crash.(The compiler is also free to change the object layout when you do this, too, though I've no idea whether any of them do.)
Forced to do by Microsoft C and C++ that mangle names.
Of course there are reasonable uses for it. Contrary, to the above you might use it to intentionally make an object opaque as a way of abstracting its details from users or when declaring use of int/long in code.
char *main = [... assembly hex codes here ...]
I pissed off a CS teaching in high school doing that.#define ELSE ;} else {
analogous to FI, to keep the appearance of semicolon as separator in the then clause.
'\0' means the NUL character, the value 0. Most of the time in C, this character is a special terminator value at the end of strings.
'\n' means the newline character, aka the line feed character, ascii value 10, which marks where one line ends and the next begins.
#define if while subscripts are just adding to pointers, and since addition is commutative, then so is the subscript operator.
Only pointer arithmetic has nothing to do with integer arithmetic, a fact which has bitten countless people in the ass over the years.In the real world, treating their semantics the same misleads newbies, and leads to bugs.