Table Of Contents:

  1. #defined function-names after function-definitions (confusing)
  2. DO NOT TRUST: that there will be warnings/errors for uninitialized variables!!!
  3. (gnu make) Makefile Recursive inclusion follies (6-17-15)
  4. (gnu make) makefile auto-creation follies (6-17-15)
  5. (xc32-gcc, plausibly others?) escaping command-line quotes, etc. (7-14-15)
  6. function-like macros with/without return-values (7-16-15)
  7. TODOs and Qs (Latest: 1-29-16)
  8. Code-Size reduction ideas... check out #limited-code hacks/tips (added 11-26-16)
  9. I HAVE NOT been keeping this ToC up to date... check out the logs!

OTHER REFERENCES:

  1. computed-gotos, more efficient state-machines than using switch() ( @Analog Two's #reprint: modern printf )

1. #defined function-names after function-definitions

Thanks to @LazyHD for the reminder: This is generally considered BAD PRACTICE. But there may be times when you'll come across it's having-been-done (and most-likely by mistake!) and then it will be quite confusing.

(See his comment, below. But, briefly, #define's should be CAPITALIZED to avoid such confusion.)

#include <stdio.h>

//Uncomment one of the '#define function' lines to see what I'm sayin'

//Uncommenting this one results in an error...
//#define function() printf("running '#define function()'\n")

//And of course, disabling both #defines, results in this being called.,,
void function(void)
{
   printf("running actual 'void function(void)'\n");
}

//Uncommenting this one results in no errors/warnings
// and *this* is called, not the actual function.
#define function() printf("running '#define function()'\n")

int main(void)
{
   function();
}

This can be royally confusing... and SHOULD NOT BE DONE INTENTIONALLY.

Say you've a function between 'void function(void)' and the second '#define function()' which happens to call function()... it'll call the actual function, but main will call the #define... right? I dunno, it's risky-business. DON'T DO THIS. More-complicated programs, however, might just cause something like this, most-likely by mistake, e.g. through #if statements...


2. DO NOT TRUST: that there will be warnings/errors for uninitialized variables!!!

GCC: This one has bit me in the butt so many times...

int function(int b)
{
   int a;
   if(b==3)
      a=3;
   return a;
}
CLEARLY: a will only be assigned a value IF b==3!

CLEARLY: "-Wuninitialized" and "-Werror=uninitialized" is designed *exactly* for the purpose of noting when a variable like int a; could be used without being assigned a value! GCC WILL NOT catch this case... at least with the versions I've used. You WILL NOT receive a warning, nor error, in this case! And, allegedly, there's no intention to fix this glitch.

There's a good discussion on it HERE.


3. (gnu make) Makefile Recursive Inclusion Follies

(initially poorly-titled: 'include $(INCLUDABLES)' wherein those 'INCLUDABLES' modify the variable 'INCLUDABLES')

Say you have a bunch of makefile 'snippets' you'd like included in a makefile.

makefile:

INCLUDABLES += inc1.mk
INCLUDABLES += inc2.mk

include $(INCLUDABLES)

http://inc1.mk:

INCLUDABLES += inc1a.mk

The end-result appears clear, at least on my system...

My search-fu is failing me. is this result expected/able to go cross-platform? cross-makes?

The end-result, on my system, is that apparently the call to 'include $(INCLUDABLES)' works with the variable 'INCLUDABLES' AS IT EXISTED when the 'call was placed'

So, inc1a.mk is never included.

(This goes against my [utter-lack-of-]understanding of make's "multipass technique", but goes completely in favor of my having an utter-lack-of-understanding of it, in the first place ;)

Thoughts?


4. (gnu make) makefile auto-creation follies

It's possible to have 'make' auto-create files it wishes to include...

e.g.

makefile:

include includeMe.mk
...

if the file 'ncludeMe.mk' doesn't exist, 'make' can try to auto-create it based on a rule...

makefile continued:

# Rules:

#Default ('make')
all:
    @echo "'make [all]'"

#Missing makefile snippet:
%.mk:
    @echo "creating missing makefile snippet"
    @touch $@"

Cool.

Now... what if you have a list of "makefile snippets" that don't yet exist and need to be auto-created?

INCLUDABLES += inc1.mk
INCLUDABLES += inc2.mk

include $(INCLUDABLES)

all:
    @echo "'make [all]'"

%.mk:
    @echo "$@ not found, auto-creating it..."
    @touch $@

Now it gets interesting... apparently, on my system, they're created in reverse-order. Does it matter? Not here, but somewhere more complex it might.

If nothing else... combined with the previous "make follies", this led to some confusion... Does 'include' actually *include the files in reverse order*?

Took a bit of experimenting, but no, it seems to include them in the right order, it just *creates* them in reverse-order. Weird.

5. (xc32-gcc, plausibly others?) escaping command-line quotes, etc.Some gcc compilations (precompiled, cross-compiled?) may require additional 'escaping' of things like quotes, when used on the command-line. E.G.

gcc -D'thing="thingString"' might have to be called as

gcc -Dthing=\\\"thingString\\\"

In the case I encountered, this is *not* the result of the way bash passes the argument to gcc, but actually something this particular compilation/configuration of gcc is doing...

Keep your eyes peeled!

6. Function-like macros with/without return-values (7-16-15)

Say you have the functions:

int withRetVal(int arg)
{
   return arg+1;
}

void withoutRetVal(int arg)
{
   <do something>;
}
Maybe there's some reason you'd prefer to put these in a macro via #define... e.g.:
#define withRetVal(arg) ((arg)+1)

#define withoutRetVal(arg) <doSomething>
FIRST, NOTE: USUALLY a #defined macro should be CAPITALIZED (see #1, above!)

Those are generally fine, as-is...

Now, what if you've got two-liners...?

We'll do these one-at-a-time, here...

#define withoutRetVal(pin)   \
   setOutput(pin); \
   turnOn(pin)
Sure, that sorta works...

When 'withoutRetVal(pin);' is replaced, it will be replaced with 'setOutput(pin); turnOn(pin);'

Note, the semicolon after withoutRetVal(pin); doesn't get replaced, it gets tagged-on after turnOn(pin)... Seems to work, right?

Well, there's several problems with this...

It looks like it could be used in an if-statement:

if (whatever)
   withoutRetVal(pin);
else
   <somethingElse>;

But, really, you've got:

if (whatever)
   setOut(pin);
   setOn(pin);
else
   <somethingElse>;

And, then, you're screwed, 'cause that else doesn't go with anything... (It can certainly get uglier than merely that, imagine nested-ifs!).

So, then, add "squiggles," right?

#define withoutRetVal(pin)   \
{  \
   setOutput(pin); \
   turnOn(pin); \
}

Done and done... RIGHT?

Sure. Done. (For now...)

Now let's consider the withRetVal case (again, multi-line):

int getPinVal(int pin)
{
     setInput(pin);
     return getInput(pin);
}

Could be written as a macro...

#define getPinVal(pin) \
{ \
     setInput(pin); \
     getInput(pin); \
}

Handy-thing... the value "returned" by these curly-brackets is the return-value from getInput(); Handy...

Done and done... right?

Except, what if you want to use this in an if-statement...

if(getPinVal(pin))
   <do something>
Then you have
if( { setInput(pin); getInput(pin); } )
Hmm... Is that legal?

Actually, I think I bit-off more than I could chew in starting to write this, I should probably test these things, again, before acting like some sort of authority. Fact-is, I'm no authority, I just figured this out the hard-way. And I've developed habits and seem to have forgotten some of the reasoning.

UPDATE: Found this:

"The `({ ... })' notation produces a compound statement that acts
as an expression. Its value is the value of its last statement."
--info cpp 3.10.4


Fact-is, there're a few more "handy" things, here and there...

For instance, say you *don't* want a return-value... but the last function-call in the macro *has* a return-value... Then you can do something like:

void doSomething(void)
{
   something1WithRetVal();
   something2WithRetVal();
}

--->

#define doSomething() \
{ \
   something1WithRetVal(); \
   something2WithRetVal(); \
   {}; \
}
The key being: Note the curly-brackets containing NOTHING at the end of the #define. This makes the doSomething() macro have no return-value, since {}; has no return-value.

Then, there's something with Parentheses... I can't recall the details off-hand (did I mention I bit off more than I could chew in writing this?)

Basically the above looks alright, again, right? But for some reason I've forgotten, I needed parentheses around those outter curly-braces...

The end-result is basically: If you want to simulate a void-function via a macro, it WORKS (in all cases I've encountered) when written like this:

#define doSomething() \
({ \
   something1WithRetVal(); \
   something2WithRetVal(); \
   {}; \
})

(Note, again, the surrounding parentheses... why was that again?)

And, if you want a non-void function-like macro, the same-goes, as I recall... just remove that {}; and it will have the same return-type as the last function called (or variable listed?)...

So, basically, habitually: I just throw in ({ <normal c-syntax function-code, with line-continuators '\'> {}; }) and it looks pretty much like a normal C function...

There are other ways to accomplish the same... 'info gcc' has a whole section on it, but the end-result is kinda ugly, as I recall... something about surrounding it with a do{ <something> }while(0) (and parens?) as I recall...

(I really should rewrite this, and rerun those experiments, and maybe even look at the notes/links I wrote in those experiments)...

It looks like I started using the ({ ... {}; }) syntax somewhere 'round 2008, so there're probably well-over a couple dozen projects that've used it this way, but ALL BASED ON various versions of GCC, so YMMV. And... I don't have a "withRetVal" case in front of me, so I'm not 100% on the part about "just remove the {};"

7. TODOs and Qs (Latest 1-29-16)

  1. SERIOUSLY: is there no such thing as something like int_native_t and uint_native_t?
    1. e.g. all I need is a few values, maybe -1, 0, and 1... Would be smartest to have it in the processor's NATIVE register-size, rather'n e.g. 'int' which is guaranteed to be at least 16-bits (right?) despite maybe being on an 8-bit processor...
    2. Optimization *might* recognize this in *many* cases, but I bet not when various functions are called from various files with this 'type' as an argument...
    3. Besides, it would make things more clear...
    4. And using int8_t isn't probably good 'nough since in e.g. a 32 bit processor, that'd require *more* instructions to extract, right...? (optimizer *might* be smart enough here...?)