share
Stack OverflowWhat is the worst real-world macros/pre-processor abuse you've ever come across?
[+176] [70] Trevor Boyd Smith
[2009-03-17 01:57:42]
[ c++ c macros preprocessor ]
[ https://stackoverflow.com/questions/652788/what-is-the-worst-real-world-macros-pre-processor-abuse-youve-ever-come-across ]

What is the worst real-world macros/pre-processor abuse you've ever come across (please no contrived IOCCC answers *haha*)?

Please add a short snippet or story if it is really entertaining. The goal is to teach something instead of always telling people "never use macros".


p.s.: I've used macros before... but usually I get rid of them eventually when I have a "real" solution (even if the real solution is inlined so it becomes similar to a macro).


Bonus: Give an example where the macro was really was better than a not-macro solution.

Related question: When are C++ macros beneficial? [1]

+1 for bringing attention to the rampant abuse I've suffered at the hands of Macros. - i_am_jorf
(37) #define true false //happy debugging :) - n0rd
Community wiki means that nobody will gain (or lose) reputation from up/down votes on this question or its answers. Many people view questions like this as cheap and easy ways to gain reputation, so if you mark it as community wiki, people are less likely to get all bent out of shape and close it. - Graeme Perrow
(2) "people are likely to get all bent out of shape and close it": Are you implying that you don't want any humorous/funny content on stack overflow? - Trevor Boyd Smith
I didn't say anything about what I want or don't want. But questions like this that are not marked CW are frequently closed quickly. If they're marked CW they tend to survive a little longer. - Graeme Perrow
This one isn't real world, but i think it deserves a (dis)honorable mention: 99-bottles-of-beer.net/language-c-c++-preprocessor-115.html - Grant Peters
(2) Just a quick point, the pre-processor is part of the language and therefore not evil/wrong to use, just like anything else. - Mr. Boy
You mean IOCCC is not part of the real world? - Timwi
[+409] [2009-03-17 03:31:59] user78859 [ACCEPTED]

From memory, it looked something like this:

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

Yes that's right, no closing braces in any of the functions. Syntax highlighting was a mess, so he used vi to edit (not vim, it has syntax coloring!)

He was a Russian programmer who had mostly worked in assembly language. He was fanatical about saving as many bytes as possible because he had previously worked on systems with very limited memory. "It was for satellite. Only very few byte, so we use each byte over for many things." (bit fiddling, reusing machine instruction bytes for their numeric values) When I tried to find out what kinds of satellites, I was only able to get "Orbiting satellite. For making to orbit."

He had two other quirks: A convex mirror mounted above his monitor "For knowing who is watching", and an occasional sudden exit from his chair to do a quick ten pushups. He explained this last one as "Compiler found error in code. This is punishment".


(1) I don't see how you would get any benefit from that macro; the compiler's just going to put them characters back in, and unless he's writing some kind of useful quine, code size wouldn't matter. - Ryan Fox
(3) Are you missing the keyword 'return' in the expansion? I think I'd expect this horror to be '#define RETURN(x) return(x);}'. - Jonathan Leffler
(87) "Compiler found error in code. This is punishment". !! Company found you ... punishment to the fellow employees ! - Learning
(227) In Soviet Russia, program compiles YOU! - Crashworks
(2) Bu- Wai- Who-. That is peverse. - Bernard
(4) Was his name Pitr by any chance? - Adrian Grigore
(53) When I read about the compiler error "punishment", the first thing I thought of was "Dobby had to iron his hands". - Graeme Perrow
(1) I think this is worth an edit... the define statement isn't correct. Other than that, pure joy! - jpinto3912
(1) In case someone things that this was one lone crazy programmer, I have also seen a very similar thing done for return statements and braces. Even worse, however, the macros were not named such that it was obvious there was actually a return that occurred! - iammichael
(124) I think programmers (myself included) would be a lot more fit if we all did 10 pushups every time a compiler found an error in our code. This might also reduce the occurrence of testing by compilation. - MikeyB
(1) What would be a good punishment exercise for breaking the build on a CI server? What about all of us doing TDD, what should we do when we get a red bar? :D - Esko Luontola
(2) Awesome. I've met Russian programmers like that. - hughdbrown
(5) That guy sounds awesome. But yeah, I don't see how this is supposed to improve code size. - Stack Overflow is garbage
(3) @MikeyB, I agree about the fitness, but at the same time, I just love "testing by compilation." Why should we do what machines can do better? - harpo
(3) My eyes! The goggles do nothing! - BIBD
Of course, I can't help but think he would have saved just as many characters if he had just removed the parenthesis ()'s from around the return values; which are of course, not necessary in C. :-D - BIBD
(4) I can assure you, that person wasn't a typical Russian programmer. We REAL Russian programmers tend to punish ourselves with kettlebell exercises and (occassionally) with horseshoe bending (though it's considered more of an Architect thing) :)) - mlvljr
(3) @mlvljr: Whimp! Anyone can bend a horseshoe, us Irish programmers STRAIGHTEN horseshoes! - Binary Worrier
@Binary Worrier: It makes one worry :) - mlvljr
(1) HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA‌​HAHAHAHAHA ! Can't stop laughing, reading again and again and it's just so similar to a type of Russian friends I have! - Poni
Really, you made that up. C'mon! LOL - Vinicius Kamakura
I'm probably late but... ":syntax off" turns Syntax Highlighting Off in VIM. - dsocolobsky
1
[+274] [2009-03-17 02:38:07] i_am_jorf

My worst:

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

I spent two days of my life tracking down some multi-threaded COM ref-counting issue because some idiot put this in a header file. I won't mention the company I worked for at the time.

The moral of this story? If you don't understand something, read the documentation and learn about it. Don't just make it go away.


I've done this for testing! But atleast it was conditional on something like TESTING - Preet Sangha
(146) @Joshua: If you run this code in a multithreaded environment, you just might unintentionally do that - 1800 INFORMATION
(11) "If you don't understand something, read the documentation and learn about it. Don't just make it go away." - AMEN! - Paul Alexander
(2) @1800 Information: I think you'd just lose votes, which is why I can't give you one ;p - wkf
(5) Forgive me as a non-C++ programmer: Is the main problem here that a threadsafe function is converted into a non-threadsafe one? Or that InterlockedIncrement expects a pointer, so now you'll increase the pointer instead of what it's pointing at? Or both? - Tim Pietzcker
(38) The problem is that InterlockedIncrement is normally an atomic function defined in the Windows API. So when people call InterlockedIncrement, they expect to call into a function that is guaranteed to be executed atomically. Instead, someone defined a macro with the same name, which evaluates to a plain, non-atomic increment - Stack Overflow is garbage
(1) "If you run this code in a multithreaded environment, you just might unintentionally do that " thats not true: you can only miss an update -> less votes than expected ;-) - usr
2
[+166] [2009-03-17 02:04:27] Joel Spolsky
#define ever (;;)
for ever { 
   ...
}

(52) I prefer <#define forever for(;;)> so you can write <forever {...}> - paxdiablo
someone I went to school with lost marks for the EVER thing... he was choked as it was in the text book :-) - TofuBeer
(6) Isn't Pax's suggestion straight from K&R? Still, not worth the effort, I'd say. - Jon Ericson
That's actually not bad at all. I'm not using for (;;) idiom, otherwise I'd immediately add this macro to my code. - AnT stands with Russia
(1) @hayalci: In emacs lisp (and some common lisp implementations) you could to (defmacro ever ()) and then (require 'cl (ever)) - Joe D
3
[+144] [2009-03-17 04:32:05] Frank
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

Challenge: Can anyone do it with fewer defines and structs? ;-)


(19) you just wrote a java-to-c converter! horray! - Andreas Petersson
(25) Reported as "offensive." (I kid!) - user7675
(40) That is either hideously beautiful or beautifully hideous. - Chris Lutz
(1) "#define System s()" saves two characters - Adam Rosenfield
I don't believe this was "real-world" like the question author specified...but I voted up anyway! The perversity of compiling "java" in c++ is hilarious! - A. Levy
(38) @Mark - It declares public and static as nothing, void` as int, and main(x) as main(), so public static void main(String[] args) turns into int main(). Then System turns into S s;s, so System.out.println("Hello World!"); turns into S s; s.out.println("Hello World!"); which calls the println function in the F struct in the S struct. - Chris Lutz
(2) Take a look at this: mailcom.com/ioccc/chia/chia.c (download and compile it) - Roberto Bonvallet
@AndreasPetersson Java-to-C++ to be exact. - user142019
4
[+130] [2009-03-17 02:01:09] Andy White
#define private public

I've done that before. Sometimes you just need to modify a member variable or override a function in some third-party code that you can't change - and they didn't provide an accessor for you. - Michael Kristofik
I did this yesterday, and wanted to smack myself in the head for doing it. But it's only done in a small test app that uses header files from the main app. - Graeme Perrow
(30) wow for unit testing this might even be useful, even though the ghosts of object design will haunt you at night. - Epaga
(12) Hmmm, undefined behavior, easy violation of the one-definition rule, potential layout differences. Yup, this is a winner. - David Thornley
(10) So with that, I can access private and public stuff, but not protected stuff, and I can't access the stuff between the class keyword and the first access modifier. - Ken Bloom
(3) @Ken: #define class struct #define protected public - Yakov Galka
5
[+107] [2009-03-17 03:36:12] Michael McCarty
#define if while

It was joke played on someone, it wasn't found amusing by those affected


(22) #define while if would be even more insidious. - starblue
#define try #define catch(x) #define switch(x) #define if(x) #define while(x) and so on... - 1800 INFORMATION
(7) We should clarify your statement. It wasn't found amusing by the people affected. :-) - Andrew Shepherd
(6) When I did homework assignments, I often did this kind of things on purpose, just to annoy my teachers. - isekaijin
(15) This is a good prank but it won't compile if there are any "else" statements. I've found that #define if(x) if(true) is most effective. - Graphics Noob
(32) I always preferred #define sizeof(x) rand() - Jon
6
[+106] [2009-03-17 02:19:20] paxdiablo

The hideous:

#define begin {
#define end }
/* and so on */

Seriously, if you want to code in Pascal, buy a Pascal compiler, don't destroy the beautiful C language.


(45) Now you've got me wondering what languages I can simulate with a clever enough header file. - Bill the Lizard
(47) C is not beautiful. It's rather ugly. - rlbond
(27) Its beauty lies in its simplicity. It's been said it has all the speed of assembly language combined with the readability of ... assembly language :-) I prefer it over the bloated C++ (although I do prefer Java in my day job due to its huge library). - paxdiablo
(9) No really. Find Bourne's original source for the bourne shell. He did exactly this to get some kind of bastard ALGOL-like mess. - RBerteig
(1) This is actually pretty common, as far as I understand, this comes from converting legacy code from pascal, or something of the sort. I've seen it in several projects, I'm not sure why people don't just use replace... - SurDin
Am I bad person for considering #define until(x) while(!(x)) on a few occasions? (I've never done it, before you hang me!) - Bernard
@Bernard - Of course not! As a Perlite, I get frustrated when I remember I don't have until() or unless() in C. Or postfix notation. If anyone can come up with a macro to allow me to write "i++ if(i);" in C, I will give you five dollars. And a free hug. - Chris Lutz
I've seen code like this before. It was one of the first things I scrubbed out as soon as I had the time. - Anthony Giorgio
@Chris-Lutz - "i++ if(i);" is i += (i != 0); so you can do INC_IF_NOT_EQUAL(x, y) { x += x != y; } - LiraNuna
(3) #define DO for (int _i=0; _i <= 1; ++_i) { if (_i==1) ////LINE BREAK//// #define IF(cond) ; if (!(cond)) break; } ////LINE BREAK//// DO printf("a") IF (1==2); - Adrian Panasiuk
@paxdiablo: Well, I have heard it called "Portable assembly." It lives up to its name well. - Cristián Romo
Ha! Some guy I interviewed did this. And "#define not !" "#define repeat while {" "#define until(x) } (x)" etc. Thank you so much for you time... - Nick
hideous? Not to everyone! I remember seeing a suggestion to use a pair of #defines like that in a printed book. To be fair, the author mentioned that it's not a good idea, but I've seen older books where such definitions are considered almost normal. - Sergey Kalinichenko
7
[+93] [2009-03-17 02:34:46] dcw

An 'architect', very humble guy, you know the type, had the following:

#define retrun return

because he liked to type fast. The brain-surgeon used to like to shout at people who were smarter than him (which was pretty much everyone), and threaten to use his black-belt on them.


I make that typo so much I actually considered it. - Joshua
(4) rather teach your editor to autoreplace retrun into return. Ive done such hackeries to my IRC-client, at least - Tetha
(1) Hey, I think I used to work with that 'architect' as well. He eventually got reclassified senior-architect when he needed to have his ego appeased. - BIBD
(1) I had 'rn' redefined to 'rm' in bash, because I couldn't type and the 'rn' newsreader took 5 minutes to startup and connect to the server. - Martin Beckett
(2) You couldn't just open a new terminal (or switch to another vt) and do killall rn? - Joe D
@Martin There's an sl program that displays a train animation. (sl stands for "Steam Locomotive.") - Maxpm
8
[+69] [2009-03-17 10:36:22] xtofl

Real-world? MSVC has macros in minmax.h, called max and min, which cause a compiler error every time I intend to use the standard std::numeric_limits<T>::max() function.


(2) Ah, yes, that's why I had a special header with sanity-restoring #undef's after the MS-specific ones... - Pontus Gagge
(3) Solved with (std::numeric_limits<T>::max)() But yeah, pretty annoying. - rlbond
(36) Add NOMINMAX to your project properties under C/C++ -> Preprocessor -> Preprocessor Definitions. - mattnewport
@mattnewport: Thanks, I didn't even dream there was a solution to this! - xtofl
It's telling that there needs to be a solution to it, a solution specific to min and max. For each other common function that happens to have a macro shadowing it you need another "solution". - quark
Naming a function or variable "NOMINMAX" would be evil, but it could happen. There can be unforeseen casualties when you fight macros with more macros. :) - bk1e
@bk1e: it so happens that MS documents this preprocessor definition to inhibit definition of the min and max macro's... But you're right. - xtofl
(18) These macros have existed in the MS headers longer than min and max have been in the C++ Standard Library. - Richard
(4) It's even worse when four of your other external dependencies also define min/max of their own, of varying degrees of suckiness, ranging from badly-parenthesised macros to well-written templates, and one of them just has to make it impossible to be undefined or otherwise skip these... In my book the language is 50% to blame though. - Roman Starkov
9
[+58] [2009-03-17 10:22:45] mouviciel

A mix between Pascal syntax and french keywords:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

(36) #define zut_alors exit(-1) - MikeyB
(4) That is awesome and it made me laugh out loud. So, this is basically a localized French version of Basic implemented in C? - Bobby
10
[+56] [2009-03-17 04:21:08] 1800 INFORMATION

Raymond Chen has a really good rant against using flow control macros [1]. His best example is straight from the original Bourne shell source code:

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}
[1] http://blogs.msdn.com/oldnewthing/archive/2005/01/06/347666.aspx

(2) Two points: one, this paste messed up the original indentation. And two, the code looks fine for what it is: 1970s Unix C by a fervent Algol-68 fan. If _why the lucky stiff can express himself in a quirky style, why can't Steve Bourne? Of course, someone condemned to maintain it who doesn't know Algol 68 may not appreciate this chance to broaden their own tastes. - Darius Bacon
I think this might be intended as a joke by Steve Bourne rather than a suggested programming style - Martin Beckett
(2) I've seen if...else...elif...fi and case...esac before (in the very language that Bourne invented for sh), but loop...pool is a real gem. - hobbs
11
[+54] [2009-08-07 00:00:14] Andrew Y

I would like to submit for the contest a gem called chaos-pp [1], which implements a functional language by means of the preprocessor macros.

One of the examples is calculating the 500th fibonacci number entirely by the preprocessor:

The original code before preprocessor looks as this:

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

preprocessing the file we get the following result (after a rather long wait):

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}
[1] http://chaos-pp.cvs.sourceforge.net/chaos-pp/order-pp/example/bottles.c?revision=1.10&view=markup

(1) You can grab the code from CVS and take a look. I had put some more details about it into my blogpost a while ago when I stumbled upon it: bnpcs.blogspot.com/2009/02/… If not for the problem with debugging the resulting code (the problem of having hugely long lines if they are generated by such a "language"), it could have been even usable as a practical code-generator for C. - Andrew Y
I can just imagine it taking forever to compile - Paul Fultz II
12
[+52] [2009-03-17 07:35:48] David Rodríguez - dribeas

Directly from Qt:

#define slots   /* */
#define signals /* */

Really nice to interact with other libs as boost::signals... Just an example, there are many others in Qt that create funny looking code like:

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

And that is C++... but suddenly:

boost::signals::trackable

Is not valid C++ any more.


I believe it's expanded to nothing. - strager
(5) :) So it is a macro that breaks other libraries for nothing. That's even better than I expected :) - David Rodríguez - dribeas
(38) Qt is very territorial and will viciously attack other libraries that try to occupy its namespace :) - Jeremy Friesner
(21) Sadly Qt attacks libraries outside of its namespace with the use of macros - David Rodríguez - dribeas
(7) Fortunately boost::signals2 has fixed this issue ;) - bdonlan
(9) Use Q_SIGNALS and Q_SLOTS if you're afraid of this interaction. - Tadeusz A. Kadłubowski
(2) Since Qt is a really big framework there's little reason to use other libraries, especially boost::signals. Those macros make perfect sense in the code that uses Qt. If you don't want them, just disable them and use Q_WHATEVER. Not a problem at all. - CMircea
Not just boost 'signals' is used by a lot of software, why didn't they at least put them in a Qt namespace! - Martin Beckett
(1) Macros are dealt with in the preprocessor before the compiler kicks in, they escape namespaces. - David Rodríguez - dribeas
@Martin, because macros are copy-paste string replacing; the preprocessor doesn't know it's working over C++, to it it's just text. - CMircea
@iconiK, true, the signal/slots are jut tags for the MOC to pick up, they could at least have made the macro qt::signal so there was less chance of collision. ps you can build QT with a flag to rename them Q_SIGNAL and Q_SLOT - Martin Beckett
@Martin, actually MOC looks for Q_SIGNAL, Q_SIGNALS, Q_SLOT and Q_EMIT. The QtGlobal header file (not sure if this one) includes #defines for signals, slots and emit for your convenience; those can easily be disabled by a #define if they get in the way, thus your argument is not well thought out. - CMircea
13
[+50] [2009-03-17 03:02:45] MrValdez

Windows.h has a lot of functions that abused macros.


MrValdez is annoyed by the GetObject macro found in Windows.h

The GetObject macro changes the GetObject() function into GetObjectA() or GetObjectW() (depending if the build is compiled in non-unicode and unicode, respectively)

MrValdez hates having to do before the GetObject function line

#undef GetObject

Object *GetObject()

The alternative is to change the function name to something else like GetGameObject()


jdkoftinoff in the comments have nailed it: The problem is that all windows API functions are macros.

Adam Rosenfield mentioned that that the issues can be fixed by defining NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX, etc before including windows.h to remove the issues.


(3) You can suppress this but #define'ing NOGDI before including windows.h, provided of course that you don't need to use any of the various GDI functions. There are a bunch of other macros such as WIN32_LEAN_AND_MEAN, NOMINMAX, etc. that suppress other things from being defined or included. - Adam Rosenfield
Hmm. Interesting. But my point still stands, I have to remember to #define NOGDI as well as those other macros because Windows.h abused macros. - MrValdez
(1) GetObject is a pretty generic function name. Perhaps you could have used a more descriptive name given the context to avoid the collision. However, that is a pretty evil macro case. - strager
(1) It is quite annoying that win32 has all the macros to convert API names to FooA and FooW. We have the problem with SendMessage. - i_am_jorf
(6) Problem is that all windows API functions are macros. One that bit me was GetTickCount(). Since I do most of my programming outside of windows, I found all the defines in the windows headers and then made my own include file which defined them all to verify compatibility beforehand. - jdkoftinoff
(1) I've changed this post into a community wiki. GetObject() is just one macro. There are a lot more. Anone can feel free to edit the post. - MrValdez
What difference does it make if your function actually gets renamed to GetObjectA / GetObjectW? With MFC, the function SendMessage actually gets changed to SendMessageW - Mark Ingram
(1) @Mark Ingram: the problem is that if you have a header file declare a function named GetObject(), and that header doesn't include windows.h, but another file includes windows.h before your header, you'll end up with different names and a compiler or linker error. - Adam Rosenfield
Haha I just ran into another variant of this on Windows. Calling a method called "FillMemory()" for a memory test class. Actual error: Not enough actual parameters for macro RtlFillmemory. see: msdn.microsoft.com/en-us/library/aa366561(VS.85).aspx - jdkoftinoff
(12) I think we have a winner. It's real-world, it's a ridiculously bad idea, and it's affected a huge number of innocent programmers. Whoever is responsible for this gem at Microsoft should be considered a war criminal... The best part is that Microsoft didn't think twice about using such amazingly common names, like GetObject, SendMessage or CreateWindow. - Stack Overflow is garbage
I've ran into that very same problem in a class that happened to have a member function called GetNumberFormat. - dan04
14
[+45] [2009-10-29 13:26:14] vava
#define return if (std::random(1000) < 2) throw std::exception(); else return

this is just so evil. It's random, which means it fires in different places all the time, it changes return statement, which usually have some code on it that could fail all by itself, it changes innocent looking keyword that you won't ever get suspicious over and it uses exception from std space so you won't try to search through your sources to find it's source. Just brilliant.


(4) Just tested this one, at least it doesn't compile by default because of a missing include for random, and it's red-squiggled then. If you have the include by accident, however, things get worse - VC++2010 marks it still as a keyword and does not show the macro expansion tooltip, so no help from the IDE to find this :-/ - OregonGhost
I love it! Pure genius. Imagine how good you can look when you "Debug" This application when no one else has managed to. - brice
15
[+36] [2009-06-25 19:18:28] Grant Limberg

A coworker and I found these two gems in some of our code for object streaming. These macros were instantiated in EVERY SINGLE class file that did streaming. Not only is this hideous code spewed all over our code base, when we approached the original author about it, he wrote a 7 page article on our internal wiki defending this as the only possible way to accomplish what he was attempting to do here.

Needless to say, it has since been refactored out and is no longer used in our code base.

Don't be thrown off by the highlighted keywords. This is ALL a macro

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

Update (December 17, 2009):

More good news regarding this hideous macro author. As of August, the employee responsible for this monstrosity was sacked.


(3) he obviously has never heard of: "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." -Brian W. Kernighan - Trevor Boyd Smith
16
[+33] [2009-10-20 13:08:09] Thomas Padron-McCarthy

I did the following myself, and I think I learned something from it.

In 1992 or so I wrote a small Lisp interpreter. It wasn't implemented in normal C, but in an interpreted C-like language. This C-like language used the standard C pre-processor, though.

The Lisp interpreter of course contained the functions car, which is used in Lisp to return the first element in a list, and cdr, which returns the rest of the list. They were implemented like this:

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(Data were stored in arrays, since there were no structs. CONS_OFFSET is the constant 1000.)

car and cdr are used frequently in Lisp, and are short, and since function calls weren't very fast in the implementation language, I optimized my code by implementing those two Lisp functions as macros:

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

CHECK_CONS checks that its argument actually is a list, and since that one is also used frequently in the interpreter, and is short, I wrote that one too as a macro:

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONS and LISP_ERROR were also used frequently, so I made them into macros too:

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

Seems reasonable?

But then, why did the entire system crash on this line:

id2 = car(car(car(car((id1))));

I worked a long time to find the problem, until I finally checked what that short line was expanded to by the pre-processor. It was expanded to a 31370-character line, which I have here split into lines (502 of them) for clarity:

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))

(18) I optimized my code by implementing those [..] functions as macros - famous last words... - BlueRaja - Danny Pflughoeft
(3) I committed similar abuses in early versions of my Postscript interpreter. Push and pop were the functions that were so important that they should be macros. But composing an expression involving more than one of these leads to undefined behavior. The undefined behavior is only caught when compiling at -O3. And at -O3 the function versions would have been inlined anyway. - luser droog
17
[+29] [2009-09-23 14:21:35] Nik Reiman

I once had to port a C application from unix to windows, the specific nature of which shall remain unnamed to protect the guilty. The guy who wrote it was a professor unaccustomed to writing production code, and had clearly come to C from some other language. It also happens that English wasn't his first language, though the country he came from the majority of people speak it quite well.

His application made heavy use of the preprocessor to twist the C language into a format he could better understand. But the macros he used the most were defined in a header file named 'Thing.h' (seriously), which included the following:

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

...which he then used to write monstrosities like the following:

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

The entire project (~60,000 LOC) was written in a similar style -- marco hell, weird names, Olde-English jargon, etc. Fortunately we were able to throw the code out since I found an OSS library which performed the same algorithm dozens of times faster.

(I've copied and edited this answer which I originally made on this question [1]).

[1] https://stackoverflow.com/questions/143701/what-is-the-worst-class-variable-function-name-you-have-ever-encountered/194124#194124

(3) I'm rather charmed by the possessives and archaic English, for all that of course I agree the code looks terrible. - Darius Bacon
18
[+27] [2009-03-17 05:52:00] Andrew Shepherd

The worst I've ever encountered was in a product containing a suite of executables where the designated technical leader hadn't figured out libraries.

Instead, he had sets of files that were shared in several Visual Source Safe folders. He then realised they needed to behave slightly differently for each application.

There's a number of refactoring steps you could apply here.

Instead, he used #ifdefs

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }

19
[+17] [2009-03-17 02:42:32] MrValdez

The use of the LINE preprocessor to generate unique ID for messages passed over the network:

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

This is an example where the macro really was better than a non-macro solution:

In a non-macro solution classes, functions and variables have to be built to keep track of what ID the message is. The developer may or may not make the message ID tracking complicated whereas this is easier to read and debug.

In addition, its easier to add new messages just by adding the message into the source.

The disadvantage of this situation is that the file has to be included in all code that uses messages. Compile time would increase whenever a message is edited.


(8) And versions may be incompatible with each other (not good!). How come an enum didn't suffice? - strager
Both this and the Enum has the exact same problem of incompatibility. - MrValdez
(17) Now I come along and sort the #defines... and the protocol changes. Or I get the Doxygen religion and document all the message codes, and the protocol changes. At least an enum is stable under the latter change. - RBerteig
(3) @MrValdez, it's less restrictive to keep a block of enums in order, than to keep defines on the same lines relative to file start. - peterchen
I know that this is an old post, but does this even work? I mean #define will just replace message constants to LINE and only then LINE will be expanded to line number, so each time we use the same constant on different lines - it will change (to current line number)? - XzKto
20
[+16] [2009-03-17 02:20:15] Jonathan Leffler

One fairly bad example:

#ifdef __cplusplus
#define class _vclass
#endif

This allows a C structure that contains a member variable called class to be handled by a C++ compiler. There are two headers with this construct in it; one of them also contains '#undef class' at the end and the other doesn't.


(1) This is why Objective-C uses @class instead of class. - user142019
21
[+14] [2009-03-19 13:04:27] Kaz Dragon

In one year of the International Obfuscated C Coding Contest, there was an entry where the entire program was:

P

With the proviso that you could define P in the makefile to be whatever program you wanted.

As I recall, it won in one of the categories, and the next year a rule had popped up disallowing that style of entry.

(Edit: six months later or something... I'm sure the "No IOCCC" thing wasn't in the main question when I wrote this...)


22
[+12] [2010-03-11 21:34:59] cobbal

I was bored one day and was playing around with blocks in Objective-C...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

allowing "interesting" things like:

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(some function and class definitions not shown for sake of brevity)


"I was bored one day" famous developer last words :) - Richard J. Ross III
23
[+11] [2009-03-17 02:03:22] TofuBeer

The worst one I saw was the non-use :-)

Someone wrote a strcpy (I think that was it... over 10 years ago now) function inside of a method (because they didn't want the overhead of calling strcpy... sigh).

They clued in that it wouldn't work for Japanese characters so they added an "if" at the start to do ASCII or Unicode. At that point the code was about a screen long... likely killing cache coherency and erasing his supposed savings for the inlining of the code.

The code was identical save for the types (so should have used a macro).

Of course the strcpy that they wrote was much much much slower than the hand tuned assembler one that was in the standard library...

Of course if they had just done it all as a macro it could have been replaced with a call to strcpy...

Of course I quit the company (not directly because of that...)


The code was identical save for the types (so should have used a macro). No, he should have used a template. - BlueRaja - Danny Pflughoeft
(1) He should have used the built in strcpy! (and it was C code not C++ so no templates) :-P - TofuBeer
Premature optimisation is the root of all evil. - Hubert Kario
24
[+11] [2009-03-17 02:38:29] dcw

The obligatory

#define FOR  for

and

#define ONE  1
#define TWO  2
...

Who knew?


(5) But-but-but NO LITERALS IN CODE! ;) - Bernard
they still be literals mon, should name em by purpose/intent not alternate symbol. COBOL code I heard about they made variable 5 = 5 then later had code saying set 5 = 10... people where real suprised when they did var + 5 and got var + 10. - Greg Domjan
(1) Never heard of that with COBOL, only with FORTRAN. COBOL, of course, has ZERO, ZEROS, and ZEROES as reserved words, all of them meaning the exact same thing as 0. - David Thornley
Much better than "#define ONE 0". If you want a giggle, search the web for that and be surprised by the non-zero number of hits. - reuben
25
[+11] [2009-06-25 19:42:52] void

I maintain code that has gotos in macros. So a function will have a label at the end but no visible goto in the function code. To make matters worse the macro is at the end of other statements usually off the screen unless you scroll horizontally.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

What's worse is when macros hide both the goto statements as well as the definitions of the target labels. Totally magic. - reuben
I've suffered from that - but the macros looked like function calls. - Jonathan Leffler
26
[+11] [2009-09-18 06:29:13] Michael F
#define TRUE 0 // dumbass

The person who did this explained himself some years later - most (if not all) C library functions return 0 as an indication that everything went well. So, he wanted to be able to write code like:

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

Needless to say, nobody in our team (tester or developer) ever dared to glance at his code again.


(1) i blame the C library functions for making 0 "everything is OK" :P - RCIX
(6) Why not declare something like #define FLAG_SUCCESS 0? - isekaijin
27
[+10] [2009-03-17 04:08:47] Frank
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}

(3) And YOU wanted to write a runtime. Look at how much time I saved! - Bernard
(4) @Trevor: Yeah... the smart ones are still doing Java instead. runs for cover - Michael Myers
If you put the [] after args instead of before, and "#define String int argc, char*", it will compile (sadly). - Adam Rosenfield
(16) I like the other one better. This one shows something close to Java being written with a few macros. The other one shows exact Java being written with a plethora of sneaky macros and structs with function members. The first one was a cheap joke, whereas the second one was an elaborate and well-though out joke. - Chris Lutz
28
[+10] [2010-05-03 11:35:11] Rubys

By a classmate who failed to understand the rules about magic numbers:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


29
[+9] [2009-06-25 19:26:36] Steve

ASA - http://www.ingber.com/#ASA

You really have to download it to appreciate it. The entire work flow is determined by macros. It is completely unreadable. As an example -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

etc., etc.

And that is just setting up the options. the entire program is like that.


(2) Oh my god...I think I'm getting dizzy. - Michael F
30
[+9] [2009-09-18 16:38:05] rcoder

A "technical manager" who had formerly been a coder introduced the following wonderful macros into our C++ project because he thought that checking for NULL values in DOM parsing routines was just too much work:

TRYSEGV
CATCHSEGV

Under the covers, these used setjmp, longjmp, and a signal handler for SIGSEGV to emulate the ability to "catch" a segfault.

Of course, nothing in the code reset the jump pointed once the code had exited the scope of the original TRYSEGV macro invocation, so any segfault in the code would return to the (now invalid) jump_env pointer.

The code would immediately die there, but not before destroying the program stack and rendering debugging more or less pointless.


Not sure if the macros are the biggest problem here, but wow. This is heinous. - reuben
31
[+8] [2009-03-17 03:13:53] MrValdez

AI Game Programming Wisdom [1] has a chapter where macros were used to create a scripting language for finite state machines.

Since the book and code are copyrighted material, here's a Google book link [2] to the page detailing the macros (The resulting script language can be found on page 324.)

[1] https://rads.stackoverflow.com/amzn/click/com/1584500778
[2] http://books.google.com/books?id=4f5Gszjyb8EC&pg=PA326&lpg=PA326&dq=macro+ai+game&source=bl&ots=9ASPntSylj&sig=KNg7dAxVv5cRdI75yDjBaFThi7U&hl=en&ei=NRS_SZtpj4w1w4PAqA0&sa=X&oi=book_result&resnum=6&ct=result

(3) Why is that so evil? The macros simplify the code (to some extent). Good programming languages allow you to create mini-languages that mirror the problem domain. C offers you the preprocessor as the main option, unless you want to spell out the portable assembler... - Pontus Gagge
Its not evil per se. It an abuse of the preprocessor to make it do things it wasn't meant to do. - MrValdez
(9) @MrValdez: Your abuse is someone else's brilliant masterpiece. :) - MikeyB
32
[+7] [2009-07-01 05:05:46] Jim Ferrans

At Lucent, I once took a look at the source code of Steve Bourne's original Unix shell, and found he'd used the C pre-processor to make C look like Pascal or Algol. The part dealing with if statements looked like this:

#define IF   if (
#define THEN ) {
#define ELSE } else {
#define ELIF } else if (
#define FI   ; }

A friend of mine told me he'd done some maintenance on it in the mid-1990s, and it was still the same. (There's a lesson here for us in the inherent conservatism of a code base.)

Of course Steve did this as an experiment in the early days, and I'm sure would have had second thoughts if he'd written it later.

Update: According to Wikipedia's Bourne Shell article [1], the macros gave it an Algol 68 flavor. And, the full set of macros [2] is here! They apparently influenced the founders of the International Obfuscated C Code Contest.

[1] http://en.wikipedia.org/wiki/Bourne_shell
[2] http://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h

(2) That's more like Algol than Pascal - it is Algol that uses backwards keywords (like 'fi') to mark the end of constructs. The shell uses that, in general. Fun question: why is the end of a loop in Bourne shell marked by 'done' and not 'od'? - Jonathan Leffler
(3) Because 'od' stands for Octal Dump, which was a utility in Unix Seventh Edition. - kmarsh
Jonathan, I've noted this in the text ... I don't remember the details, but an Algol-like syntax was a strong possibility. Ahh, I see: 'od' was the pre-existing octal dump command. Interesting! - Jim Ferrans
This is one of the more famous early examples of preprocessor (ab)use. in the days before curly brace syntax was considered a sign of a "serious" language. - quark
this fails on 'else if' does algol have 'else if' ? - smerlin
@smerlin: Click on the "full set of macros" link to see the actual ones. You want the ELIF macro. - Jim Ferrans
The link didn't work for me, but this one does: minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.‌​h - luser droog
I've seen some professors in an officially french college distribute a "francais.h" file to students containing stuff like: #define si if and #define tant_que while to get them to "code in french". Thankfully the class never tried to cover the STL. I would have snapped if they had the students write std::chaine_de_caracteres instead of std::string. - André Caron
33
[+7] [2011-08-11 14:54:49] Peter Lawrey

I like this example, it uses the macro to approximate the value of PI. The larger the circle, the more accurate the approximation.

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

Another is the c program

c

To compile you need to define c as

-Dc="#include <stdio.h> int main() { char *t =\"Hello World\n\"; while(*t) putc(*t++, stdout); return 0; }"

34
[+6] [2009-10-23 13:31:57] Obi

Coroutines (AKA Stackless threads) in C. :) It's Evil trickery.

#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
int function(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(1, i);
    crFinish;
}

int decompressor(void) {
    static int c, len;
    crBegin;
    while (1) {
        c = getchar();
        if (c == EOF)
            break;
        if (c == 0xFF) {
            len = getchar();
            c = getchar();
            while (len--)
            crReturn(c);
        } else
        crReturn(c);
    }
    crReturn(EOF);
    crFinish;
}


void parser(int c) {
    crBegin;
    while (1) {
        /* first char already in c */
        if (c == EOF)
            break;
        if (isalpha(c)) {
            do {
                add_to_token(c);
        crReturn( );
            } while (isalpha(c));
            got_token(WORD);
        }
        add_to_token(c);
        got_token(PUNCT);
    crReturn( );
    }
    crFinish;
}

35
[+5] [2009-06-25 18:42:48] Dolphin
switch (device_id)
{
#ifndef PROD_1
#ifndef PROD_2
#ifdef PROD_3
  case ID_1:
#endif

#ifdef PROD_4

#ifdef PROD_5
  case ID_2:
  case ID_3:
  case ID_4:
#elif defined(PROD_4)
#ifndef PROD_6
  case ID_1:
#endif // PROD_6
  case ID_5:
#endif

  case ID_6:
#endif

#ifdef PROD_7
  #ifndef PROD_8
    case ID_7:
  #endif
#endif

(names changed to protect the not so innocent)

Notice that we haven't even gotten to any code yet, this is just to get to the first actual bit of code. This actually happens (in almost, but not exactly the same way) for several functions, each of which, in the end only have 4 possible variations (which are also mostly copy/paste with slight variations and #ifdefs of their own).


That's just beautiful. And for what porpoise? - luser droog
If only I could type just a smily here! - luser droog
36
[+4] [2009-08-07 13:25:03] Tadeusz Kopec for Ukraine
#define interface struct

in some of Optima++ headers (Optima++ is/was a Watcom/Powersoft IDE I had to work with).


(1) One of the Windows header files also #defines interface to something. - bk1e
+1 This error caught me and one of my (much more knowledgeable) colleages tracked it down. - John
37
[+4] [2009-09-18 13:05:16] eduffy
#define FLASE FALSE

The programmer was a bad typist, and this was his most common mistake.


I've known developers to alias "mroe" (more) and such in the command line environment, but doing it in code takes the cake. - Curt Nichols
(10) Hey, everoyne nakes miskates! - Konamiman
38
[+4] [2010-09-18 22:17:40] Gabriel Schreiber

Have to do this from memory, but was about like this: Working with a lib for writing Symbian apps. Hidden in a header file you needed to include was this little gem:

// Here come the register defines:
#define C <something>
#define N <something>
<two more single letter defines>

In our code the loading of a file with a hardcoded filename failed. When we changed the file location from C to D drive, it magically worked...


39
[+3] [2009-09-18 06:00:29] Motti
#define unless(cond) if(!cond)
#define until(cond) while(!cond)

Used:

unless( ptr == NULL) 
    ptr->foo();

(6) Not even safe: unless (a + b == c) does not do what you think! - Jonathan Leffler
(6) Safer if changed to: #define unless(cond) if(!(cond)) #define until(cond) while(!(cond)) - Joel
(2) That's actually from Perl, so I can see what the author is getting at. Not evil actually (disregarding Jonathan's comment, which isn't difficult to fix), but quite readable (I can't say the same for the rest of the language) - new123456
40
[+3] [2009-11-24 22:44:17] Brian Postow

The worst I've seen is in my current project where there are a whole lot of cases of:

#if PROGRAMA
     .
     .
    if(...)
    {
     .
     .
     .
#else
    .
     .
    if(...)
    {
     .
     .
     .
#endif
     }

Yeah, he closes 2 opens with a single close.


41
[+2] [2009-03-17 02:35:44] sipsorcery

When I first came across macros in C they had me stumped for days. Below is what I was faced with. I imagine it makes perfect sense to C experts and is super efficient however for me to try and work out what exactly was going on meant cutting and pasting all the different macros together until the whole function could be viewed. Surely that's not good practice?! What's wrong with using a plain old function?!

#define AST_LIST_MOVE_CURRENT(newhead, field) do { \
typeof ((newhead)->first) __list_cur = __new_prev; \
AST_LIST_REMOVE_CURRENT(field); \
AST_LIST_INSERT_TAIL((newhead), __list_cur, field); \
} while (0) 

42
[+2] [2009-03-17 04:30:47] Mikeage

Good macros: (although personally I dislike the double parentheses required to use this syntax; I prefer either vararg macros (C99 only) or something like PRINTF_0, PRINTF_1, etc, depending on the number of arguments)

#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif

Reduces code size / execution time (the first more than the second) for non-debug build; also prevents leaking debug text strings which may pose a smallish security risk


Corrected. Escape the _'s with \. - strager
I like #define D(s) do{s;}while(0) which is used as D(printf(...)); The extra parens make sense... - RBerteig
you can also define PRINTF as "printf" if debugging is on and as "(void)" if it is not. Then it works with any number of arguments, you get code like "(void)(1,2,3,4)" which does nothing. - Marten
@Marten: unless that is something like "(void)(LookupDebugId(id), ConvertToString(id))", in which case "ConvertToString" will still be called, just its return value is ignored, and "LookupDebugId" could be non-existent. If you are in Visual Studio land, you have __noop, which does what you want. - Simon Buchan
Also remember that printf(x) can have strange, and potentially catastrophic, results if there are any percent signs in x. - David Thornley
43
[+2] [2009-03-17 04:34:37] Aaron

Related to Raymond's rant is the following horrible (in my opinion, of course) macro:

#define CALL_AND_CHECK(func, arg) \
    int result = func(arg);       \
    if(0 != result)               \
    {                             \
        sys.exit(-1);             \
    }                             \

I was pretty new to the practice of using macros and used this macro, but I expected the function that I passed to it to fail. And I was doing it in a background thread, so it stumped me for days why my entire app was "crashing".

As an aside, if only std::tr1::function was around when this macro was written, I would have a week of my life back!


Bear in mind that using CALL_AND_CHECK() twice in one scope will result in multiply defining result, and even if it didn't if (x) CALL_AND_CHECK(foo, y) else CALL_AND_CHECK(foo, z) would have surprising results. - David Thornley
44
[+2] [2009-08-07 12:58:01] William Casarin

I once put together this horrifying C++ code which used macros to help hook functions into the import table of DLLs.


#define ARGLIST(...) __VA_ARGS__

#define CPPTYPELESSARG(typelessParams) thisptr, typelessParams
#define CPPTYPEDARG(typedParams) void* thisptr, typedParams
#define CPPTYPELESSNOARG thisptr
#define CPPTYPEDNOARG void* thisptr

#define CPPHOOKBODY(hookName, params) void *thisptr; \
    __asm { mov thisptr, ecx } \
    return On##hookName ( params );


#define CHOOKBODY(hookName, typelessParams) return On##hookName( typelessParams );

#define CPPHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDARG(typedParams), typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSARG(typelessParams)))

#define CPPHOOKNOARG(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDNOARG, typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSNOARG))

#define CDECLHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __cdecl, __cdecl, CHOOKBODY(hookName, typelessParams))

#define CDECLFUNC(name, address, returnType, args) \
    typedef returnType (__cdecl *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define CPPFUNC(name, address, returnType, args) \
    typedef returnType (__thiscall *name##Ptr)(void* thisptr, args); \
    name##Ptr name = (name##Ptr) address;

#define STDFUNC(name, address, returnType, args) \
    typedef returnType (__stdcall *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define STDHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __stdcall, __stdcall, CHOOKBODY(hookName, ARGLIST(typelessParams)))

#define HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, hookParams, fnPtrCall, hookCall, hookBody) \
        typedef returnType (fnPtrCall *##hookName##OrigPtr )( typedParams ); \
        class hookName : public IHook \
        { \
        public: \
            typedef hookName##OrigPtr func_type; \
        private: \
            static void* m_origFunction; \
            static bool m_bModifyImport; \
            static std::string m_lib; \
            static std::string m_importFunc; \
            static std::string m_sHookName; \
            static returnType hookCall hookName##FnHook ( hookParams ) \
            { \
                hookBody \
            } \
            static bool ImplIsModifyImport() { return hookName::m_bModifyImport; } \
            static void ImplSetModifyImport(bool bModify) { hookName::m_bModifyImport = bModify; } \
            static const std::string& ImplGetLibName() { return hookName::m_lib; } \
            static const std::string& ImplGetImportFunctionName() { return hookName::m_importFunc; } \
            static void ImplSetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static void* ImplGetOriginalAddress() { return hookName::m_origFunction; } \
            static returnType On##hookName ( typedParams ); \
            static void* ImplGetNewAddress() { return hookName::##hookName##FnHook; } \
            static const std::string& ImplGetHookName() { return hookName::m_sHookName; } \
        public: \
            hookName() \
            { \
                InjectHookRef.AddHook((IHook*)this); \
                hookName::m_lib = importLib; \
                hookName::m_importFunc = importFunc; \
                hookName::m_sHookName = #hookName; \
                hookName::m_origFunction = NULL; \
                hookName::m_bModifyImport = true; \
            } \
            virtual bool IsModifyImport() const { return hookName::ImplIsModifyImport(); } \
            virtual void SetModifyImport(bool bModify) { hookName::ImplSetModifyImport(bModify); } \
            virtual const std::string& GetHookName() const { return hookName::ImplGetHookName(); } \
            virtual const std::string& GetLibName() const { return hookName::ImplGetLibName(); } \
            virtual const std::string& GetImportFunctionName() const { return hookName::ImplGetImportFunctionName(); } \
            virtual void* GetOriginalAddress() const { return hookName::ImplGetOriginalAddress(); } \
            virtual void* GetNewAddress() const { return hookName::ImplGetNewAddress(); } \
            virtual void SetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static func_type GetTypedOriginalAddress() { return reinterpret_cast(hookName::m_origFunction); } \
        }; \
        void* hookName::m_origFunction = NULL; \
        bool hookName::m_bModifyImport = false; \
        std::string hookName::m_lib; \
        std::string hookName::m_importFunc; \
        std::string hookName::m_sHookName; \
        static hookName g##hookName##Inst;

Which in turn allowed me to do this:

CPPHOOK(gIH, "SimEngine.dll", "?AddEntity@Player@@UAEXPAVEntity@@@Z", PlayerAddEntity, void, void* ent, ent);

/* Called when the engine calls Player::AddEntity(entity) */ void PlayerAddEntity::OnPlayerAddEntity(void *thisptr, void *ent) { unsigned int id = getPlayerID(thisptr);

gIH.GetLog()->Info("Player %d adding entity %s.", 
    getPlayerID(thisptr), getEntityName(ent));

gPlayers[id] = thisptr;

/*if( id == 2 && gPlayers[1] && gPlayers[2] )
    EntitySetOwner::GetTypedOriginalAddress() (ent, gPlayers[1]);*/
//gEnts[ent] = Entity(ent, Vector3f());

PlayerAddEntity::GetTypedOriginalAddress() (thisptr, ent);

}


45
[+2] [2009-08-09 01:47:59] Adam Batkin

Anything using sendmail and its magic configuration syntax


Yea, that's pretty bad. m4's syntax isn't great. I once dug into it's docs thinking that I could use it for some other stuff, and found that the authors didn't include a looping construct because you could build one of your own using recursion. I didn't use m4 for anything after that. - Michael Kohne
46
[+2] [2009-08-20 17:11:14] i_am_jorf

I'm adding another one that has started to annoy me over time:

#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))

And that's if they get it right; I've seen versions with all possible permutations of parenthesis present or not. I've seen it defined twice in the same header file.

Mainly my argument applies to Windows (though I assume other OS SDKs have something similar), where just about everyone seems to feel the need to define this macro in their project's header, and I don't understand why.

WinNT.h (which is included by Windows.h) defines a very nice version that does some template voodoo to cause compile time errors if you pass a pointer type instead of an array.

Of course it falls back to exactly what I wrote above if you are building a C program, but I would still not redefine something the SDK has by default for no reason.


I've found that #define DIM(x) (sizeof x / sizeof * x) has saved me a lot of typing. - Jamie
(2) I don't have a problem with the idea, just use the one that comes with your SDK. If you want to save typing, try #define DIM(x) ARRAYSIZE(x). - i_am_jorf
Dragging in the whole of <windows.h> just for this macro seems somewhat excessive. You'll also be going out of your way to write unportable code. - Chris Oldwood
(1) If you're writing code on windows, you're already dragging in windows.h. Unless you're writing small console apps and the like. I mean, you can try to stick to just the crt functions, but eventually you'll want to do something you need win32 for. - i_am_jorf
I just don't understand why you can't use a function instead. Plus, a function would be safer than the macro since it won't work with pointers. - Paul Fultz II
47
[+2] [2009-10-23 13:43:54] WillW
#define "CR_LF" '\r'

That confused the hell out of me for a while!


48
[+2] [2010-04-01 10:21:42] Nick Dixon

A past employer found there were no implementations of BASIC-PLUS [1] on modern Unix systems, so they tried to re-implement it using C pre-processor macros:

#define IF if(
#define THEN ) {
#define ENDIF }
#define GOTO goto L

...etc.

Horrific.

[1] http://en.wikipedia.org/wiki/BASIC-PLUS

I once worked on a codebase that was translated from Pascal into C which tried to keep the Pascal syntax using this approach. - Chris Oldwood
49
[+2] [2010-04-06 21:23:39] Muxecoid

This is taken from a popular open source program. In fact it makes some parts of the code more readable by hiding the ugly legacy.

#define EP_STATUS    CASTLING][(BOARD_FILES-2)
#define HOLDINGS_SET CASTLING][(BOARD_FILES-1)

I guess there is nothing really bad here, I just find it funny.

http://git.savannah.gnu.org/cgit/xboard.git/tree/common.h


50
[+2] [2010-04-06 21:38:12] timday

See this answer [1] re how a dyslexic colleague made life easier for themselves with a common header file full of things like #define fasle false.

[1] https://stackoverflow.com/questions/2163402/tips-for-a-programmer-with-dyslexia/2163489#2163489

51
[+2] [2011-03-28 10:14:06] iammilind
#define PROCESS_AND_RETURN(X) \
X.process(); \
// Important: Return only after invoking virtual method process() \
return X

Due to "Important" comment, the macro never returns the object and CRASH!


52
[+1] [2009-03-17 03:22:06] Jonathan Leffler

Another piece of 'creative' use of the preprocessor, though it is more in the terminology employed than in the mechanics (which are incredibly mundane):

/***********************************************************************
 * OS2 and PCDOS share a lot of common codes.  However, sometimes
 * OS2 needs codes similar to those of UNIX.  NOTPCDOS is used in these
 * situations
 */

#ifdef OS2
#define PCDOS
#define NOTPCDOS
#else /* OS2 */
#ifndef PCDOS
#define NOTPCDOS
#endif /* PCDOS */
#endif /* OS2 */

Genuine code - I thought I'd removed it, but apparently not. I must have done so out in some temporary branch and not gotten permission to check it back into the main code. One more item for the 'to do' list.


53
[+1] [2009-03-17 04:53:27] Coxy

Found in declarations, to much confusion:

NON_ZERO_BYTE         Fixed(8)  Constant('79'X),

Found later:

IF WORK_AREA(INDEX) = ZERO_BYTE THEN  /* found zero byte */ 
   WORK_AREA(INDEX) = NON_ZERO_BYTE ; /* reset to nonzero*/

54
[+1] [2009-03-17 05:33:40] Dan O

The worst abuses (and I'm guilty of doing this occasionally) is using the preprocessor as some sort of data file replacement, ie:

#define FOO_RELATION \  
BAR_TUPLE( A, B, C) \  
BAR_TUPLE( X, Y, Z) \ 

and then somewhere else:

#define BAR_TUPLE( p1, p2, p3) if( p1 ) p2 = p3;
FOO_RELATION
#undef BAR_TUPLE

which will result in:

if( A ) B = C;
if( X ) Y = Z;

This pattern can be used to do all sorts of (terrible) stuff... generate switch statements or huge if else blocks, or interface with "real" code. You could even use it to ::cough:: generate a context menu in a non-oo context menu system ::cough::. Not that I'd ever do anything so lame.

Edit: fixed mismatched parenthesis and expanded example


GCC actually uses that style internally. Its useful in moderation, but should definitely be well documented. - Jeff M
Is the mismatched close parenthesis intentional? - Jonathan Leffler
55
[+1] [2009-03-17 06:03:10] Johan

Try to debug big project that really loves macros, and there is a lot of macros that calls other macros that calls other macros etc etc. (5-10 levels of macros was not that uncommon)

And then top it up with a lot of #ifdef this macrot #else that macro, so if you follow the code it like a tree of different paths it can go.

The only solution is most cases was to precompile and read that instead....


56
[+1] [2009-08-07 00:56:26] Grant Peters

I agree that for the most part, macros are horrible to use, but i have found a few instances where they have been useful.

This one is actually brilliant IMHO, as you can only get something similar with sprintf, which then requires resource allocations and whatnot, plus, all work is done entirely by the preprocessor

// Macro: Stringize
//
//      Converts the parameter into a string
//
#define Stringize( L )          #L


// Macro: MakeString
//
//      Converts the contents of a macro into a string
//
#define MakeString( L )     Stringize(L)


// Macro: $LINE
//
//      Gets the line number as a string
//
#define $LINE                   MakeString( __LINE__ )


// Macro: $FILE_POS
//
//      Gets the current file name and current line number in a format the Visual Studio
//      can interpret and output goto
//
// NOTE: For VS to properly interpret this, it must be at the start of the line (can only have whitespace before)
//
#define $FILE_POS               __FILE__ "(" $LINE ") : "

The other that I loathe to use, but find it extremely useful is doing something like this, which basically allows me to quickly generate templates that have a variable number of template parameters

#define TEMPLATE_DEFS    typename ReturnType
#define TEMPLATE_DECL   ReturnType
#define FUNCTION_PARAMS void
#define FUNCTION_PASS   
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer0
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1
#define TEMPLATE_DECL   ReturnType, P1
#define FUNCTION_PARAMS P1 param1
#define FUNCTION_PASS   param1
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer1
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2
#define TEMPLATE_DECL   ReturnType, P1, P2
#define FUNCTION_PARAMS P1 param1, P2 param2
#define FUNCTION_PASS   param1, param2
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer2
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2, typename P3
#define TEMPLATE_DECL   ReturnType, P1, P2, P3
#define FUNCTION_PARAMS P1 param1, P2 param2, P3 param3
#define FUNCTION_PASS   param1, param2, param3
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer3
#include "Callback.inl"

// and so on...

Although this makes it kind of horrible to read "Callback.inl", it does completely eliminate rewriting the same code with a different number of arguments. I should also mention that "Callback.inl" #undefs all of the macros at the end of the file, hence, the macros themselves won't interfere with any other code, it just makes "Callback.inl" a little harder to write (reading and debuging isn't too hard though)


57
[+1] [2009-09-18 03:36:17] reuben

At the time it seemed like a good idea to "pass" a macro as an argument into another macro. (I just couldn't stand the thought of defining a list of values in multiple places.) The code here is contrived (and not very motivating), but gives you the idea:

#define ENUM_COLORS(CallbackMacro) \
    CallbackMacro(RED)   \
    CallbackMacro(GREEN) \
    CallbackMacro(BLUE)  \
    // ...

#define DEFINE_COLOR_TYPE_CALLBACK(Color) \
    Color,

enum MyColorType {
    ENUM_COLORS(DEFINE_COLOR_TYPE_CALLBACK)
};

void RegisterAllKnownColors(void)
{
#define REGISTER_COLOR_CALLBACK(Color) \
    RegisterColor(Color, #Color);

    ENUM_COLORS(REGISTER_COLOR_CALLBACK)
}

void RegisterColor(MyColorType Color, char *ColorName)
{
    // ...
}

Missing backslashes on last two #define lines? - Jonathan Leffler
Yep. Added in the missing backslashes. - reuben
58
[+1] [2009-09-23 14:36:50] Skizz

It's not a C macro but...

Many years ago I had the fun task of porting the original Transport Tycoon from the PC to the Mac. The PC version was written entirely in assembler so we had to go through the whole source code and port it to 'PC' C code first and then port that to the Mac. Most of the code was OK, even object orientated in places. However, the world rendering system was unbelievable. For anyone who's not played the game, the world can be viewed at one of three zoom levels. The code for this was something along the lines of:

macro DrawMacro <list of arguments>
   a couple of thousand lines of assembler with loads of conditionals
   based on the macro arguments

DrawZoomLevel1:
   DrawMacro <list of magic numbers>

DrawZoomLevel2:
   DrawMacro <list of more magic numbers>

DrawZoomLevel3:
   DrawMacro <list of even more magic numbers>

We must have been using a slightly older version of MASM as the macro would crash the assembler when we tried to assemble it.

Skizz


59
[+1] [2010-02-02 14:50:30] Hans Insulander

The NFS code in BSD-kernels use goto between macros. It's still in use, and the code actually works. I know of several persons who have tried to clean it up, but all of them have given up after a while - it's just too messy.

You can see it here: http://www.openbsd.org/cgi-bin/cvsweb/src/sys/nfs/nfsm_subs.h?rev=1.43


60
[+1] [2010-03-11 22:08:59] bta

I once saw a macro package that would alias every C keyword to let you effectively program in Klingon. That's right, Klingon. (Un)fortunately, the project was abandoned and taken down several years ago.


61
[+1] [2011-04-14 13:43:17] Frank Szczerba

The driver code for an ASIC I used about 10 years ago had a lot of sections that looked like:

int foo(state_t *state) {
    int a, b, rval;

    $
    if (state->thing == whatever) {
        $
        do_whatever(state);
    }
    // more code

    $
    return rval;
}

After a lot of head scratching we finally found the definition:

#if DEBUG
#define $ dolog("%s %d", __FILE__, __LINE__);
#else
#define $
#endif

This was hard to find, because none of the source files that used it had any include files. There was a file called top.c source file that looked like:

#include <namechanged.h>
#include <foo.c>
#include <bar.c>
#include <baz.c>

Sure enough, this was the only file referenced in the Makefile. Whenever you changed anything, you had to recompile everything. This was "to make the code faster".


62
[0] [2009-03-19 15:22:26] Greg Domjan
#define protected private

Seemed like a good idea sometimes, but if you need to, you should probably just string replace anyway. Protected is fairly evil, allowing internal access to descendants isn't much better than just making the items public...


63
[0] [2009-06-25 19:48:11] Greg D

Any macro that uses the token concatenation operator ##.

I saw one that a colleague of mine had the pleasure of working with. They tried to make a custom-implementation of string interning, so they re-implemented strings using a massive number of macros that (of course) didn't work properly. Trying to figure out what it did made my eyes explode because of all the ##'s scattered about.


I used ## a fair bit, but none of my macros are particularly complex - Just stuff to generate a simple getter or setter function. - Michael Kohne
64
[0] [2009-07-01 14:19:49] isekaijin

I have used header files as big macros:

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h
// uses param1 and param2

I have also created recursive header files.

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h"
#if ... // conditional taking param1 and param2 as parameters
#define temp1 param1
#define temp2 param2
#define param1 ... // expression taking temp1 and temp2 as parameters
#define param2 ... // expression taking temp1 and temp2 as parameters
#include "killer-header.h"
// some actual code
#else
// more actual code
#endif

65
[0] [2009-09-18 03:05:30] Michael Kohne

I'm not fond of the Boost Preprocessor stuff. I attempted once to figure out how to use it (we had Boost in the project anyway...), but as near as I could tell, using it would make my error messages SO unreadable that it wasn't worth it.

I liked the idea of the equivalent of looping macros, but it was just too much.


66
[0] [2009-09-18 16:45:45] Brock Woolf
#undef near
#undef far

When I was new to game programming I was writing a frustum for a camera class is a game that I wrote, I had really strange errors in my code.

It turns out that Microsoft had some #defines for near and far in windows.h which caused my _near and _far variables to error on the lines that contained them. It was very difficult to track the problem down because (I was a newbie at the time) and they only existed on four lines in the whole project so i didn't realise right away.


67
[0] [2009-10-20 11:54:25] Pierre Guilbert

I found it in libtidy,:

 /* Internal symbols are prefixed to avoid clashes with other libraries */
 #define TYDYAPPEND(str1,str2) str1##str2
 #define TY_(str) TYDYAPPEND(prvTidy,str)

 TY_(DocParseStream)(bar,foo);

The problem is that visual studio 2005 and maybe other ide go to definition and go to declaration features only find the #define TY_(...) and not the desired DocParseStream declaration.

Maybe it is safer this way.

I think they should put a prefix for each function and not call a macro to do the job.. it's cluttering the code.. but maybe I am wrong about that. What do you think..?

Ps: It seems that almost all the internal function const and others are prefixed using this.. My colleague just told me that it is usual.. wtf? Maybe I missed something.


68
[0] [2011-05-18 18:59:02] Allbite

Be gentle, I wrote this as the only way I can think of to generically capture exceptions.

I use it to capture and stop exceptions from propagating out of my public interface functions...

/// Catch all generic exceptions and log appropriately.
/// Logger is insulated from throwing, so this is a NO THROW operation.
#define CatchAll( msg ) \
    catch( const Poco::Exception &e )   \
    {   \
        try{ LogCritical( Logs.System(), std::string( e.displayText() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch( const std::exception &e )    \
    {   \
        try{LogCritical( Logs.System(), std::string( e.what() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch(...)  \
    {   \
        try{ LogCritical( Logs.System(), std::string( "Exception caught in " __FUNCTION__ ". " ).append( msg ) );}catch(...){assert(0);}    \
    }   

I dislike the complexity and I hate macros, but how else would you "do" a generic catch handler? This isn't meant to be the end-all, this is just my generic catch handler to insulate legacy public functions and quickly add at least some level of protection when I know the function is getting invoked across a boundary which might throw up if a C++ exception were to be thrown (your welcome, JNI).

So does it make you run and hide, or is it the only way to do something like this?

Basically...

try{
// some block of code capable of throwing
}
CatchAll()

(1) in java you would do a generic catch by doing catch on the Exception class. and that would catch everything. in your code, i'm guessing that your exception are not all derived from std::exception? - Trevor Boyd Smith
69
[-1] [2009-03-17 04:29:56] ErgoSum

Anything that uses the Token concatenation operator ##. I've seen this used to hack together psudo-template systems in C++ and other horrible things. The worst thing about using it is how impossibly cryptic your error messages become.

I have seen one good use for it however. There was a macro #MONITOR_COMPONENT(classname) that generated classes at compile time that would inherit from a predefined monitor class and classname and that would autoregister with a singleton class that was used to monitor each component.

Did it work? Yes, was it the nicest way of doing it.. probably not.


The macro in this case to auto-register the class into a singleton is not that bad of an idea, see my first stackoverflow question as to why: stackoverflow.com/questions/77817/… . - X-Istence
So I'm guessing you are also anti assert()? (hint, its usually a macro that looks just like what you dislike) :) - user50049
I did say in my second paragraph that this was a good use for the operator. I still don't think its the best possible solution to the problem. - ErgoSum
70