
Preprocessor magic: Default Arguments in C - llambda
http://lefteris.realintelligence.net/?p=593&
======
Arelius
They call it pre processor magic because it's difficult to maintain. Years
ago, after writing an OR! Using C pre processor magic, I took a vow: Never
again!

Do yourself a favor, either write clean, portable, clear and concise C code,
or use a real pre-processor. The only time you should be using pre processor
magic anyways is in a large project that's not a library anyways. So at that
point it's pretty trivial to just use a proper pre-processor.

~~~
cube13
Preprocessor magic is pretty much required if you want to write multiplatform
code. I work on code for Solaris, Linux, and Windows, and makes life much
easier to use #defines to standardize the OS calls.

~~~
ori_b
Or you write platform specific code in it's own files, and link it in
conditionally.

    
    
        port-linux.c
        port-win32.c
        port-solaris.c
        myprog.c
    

and just compile/link port-$TARGET.c into your program. The code tends to be
cleaner, and the platform knowledge is concentrated in one place.

~~~
Arelius
In my experience this is a much better approach. Most modern compilers can
inline across linker boundaries anyways, so it's not a real performance issue
either.

~~~
LefterisJP
Yes having platform specific code in its own header source and just #ifdef the
includes provides much cleaner and nicer code

~~~
ori_b
Don't even do that -- have one header that all the platform interfaces
implement without ifdefs.

Keep the conditional compilation in the makefiles, not in the source.

------
LefterisJP
Hey all,

I am the author of the linked blog. Many nice comments in here, but may I
start by a question of my own about hackernews itself. I had submitted this
link myself 6 days ago after making the post. Can a link be resubmitted
multiple times? The title was a bit different but the link was the same. I am
new to the site and want to learn the way it works.

As for the comments by many people, it's a given that this will not appeal to
all. Heck to most people especially C++ only programmers it will look ugly.
The fact is that if for one reason or another you want to provide functions
that have default arguments this is a neat and nice way that works for C99.

As for needing default arguments, well there might be cases where having them
is just a way to spoil or even confuse the programmer. But consider an API. An
API of a GUI library. Do you REALLY want to be giving all the customizations
offered by the library for every single widget/element? Or do you want a
TextBox of size(100,100) at position(200,50) and you are done by letting the
default arguments handle all the rest?

~~~
rcfox
It looks like the submitter added a & to the end of the URL. This is generally
considered to be cheating. I guess it worked out this time though... There are
probably a few articles out there that will tell you the best time to submit a
link. If you're really worried about getting karma/clicks, you should consult
one of them.

~~~
LefterisJP
No no, I don't care about karma, just discovered the site recently and wanted
to learn how it works. Exposure on the other hand is always a nice thing. I am
actually really glad to the submitter since this generated a nice discussion
in the blog itself and made me fix a few things I was wrong about.

------
haberman
> The advantages of having default arguments is not something that needs
> convincing. It's just very nice and convenient to have them.

The Google Style Guide disallows default arguments, and I find their rationale
convincing enough that I never use default arguments in my own code:
[http://google-
styleguide.googlecode.com/svn/trunk/cppguide.x...](http://google-
styleguide.googlecode.com/svn/trunk/cppguide.xml#Default_Arguments)

~~~
gaius
_Default parameters are more difficult to maintain because copy-and-paste from
previous code may not reveal all the parameters_

I am surprised this is an issue at Google.

~~~
Arelius
Why? Google, like most companies, Google is made up mostly ofretty standard.
Most programmers enjoy referencing existing code to help understand how an
interface works.

Just because they have more stringing hiring practices doesn't make their
engineers some superhuman level of programmer.

~~~
mistercow
Referencing existing code is one thing. Copy/pasting that code, or writing new
code based on it, without actually looking at the documentation to know what
you're doing, is another thing entirely.

~~~
Arelius
The issue is not what tends to be the correct way to properly code, but how in
fact people end up coding.

It seems that many engineering decisions are made at google, to minimize the
amount of damage a particular programmer can do. This suggests that while
Google does/may have some very good people running the place, they also have
quite a few programmers whom are mediocre at best.

These choices are about building an environment that forces a programmer to do
things the right way, rather then expecting them to do such on their own.

------
aidenn0
c99 makes this much, much easier than they think:

    
    
       #define ARG_16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,...) q
       #define COUNT(...) ARG_16(x,##__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
       #define PASTE2(a,b) a ## b
       #define CALLFN(name,nargs,...) PASTE2(name,nargs)(__VA_ARGS__)
       #define FOO(...) CALLFN(foo,COUNT(__VA_ARGS__),__VA_ARGS__)

~~~
LefterisJP
As I told you inside the comments in the blog itself, what is x in the
definition of COUNT(...) ?

Also it seems that you did not read the topic correctly because even if you
tried to apply such a method it would fail for the no arguments case, which is
a big part of the bulk of the first method.

If I don't get something please feel free to explain

------
snorkel
Bah. I prefer poor man's currying instead, just wrap the function.

------
0xABADC0DA
This is kind of neat to get named arguments in C as well.

Instead of calling:

    
    
        foo_init(1, 'a', 1.0);
    

You can write:

    
    
        foo_init(.arg1=1, .arg3=1.0, .arg2='a');
        foo_init(.arg3='c');
        // etc
    

edit: didn't see this in the blog comments, wasn't trying to steal credit ;-P

~~~
cygx
The combination of compound literals and variadic macros is indeed pretty
neat. It can also be used to implement Java-style variadic functions (ie when
the variadic parameters have a single type):

    
    
        #define sum(...) \
            sum_(sizeof ((int []){ __VA_ARGS__ }) / sizeof (int), (int []){ __VA_ARGS__ })
        
        int sum_(size_t count, int values[])
        {
            int s = 0;
            while(count--) s += values[count];
            return s;
        }
    

You'd call the macro as

    
    
        int s = sum(1, -32, 5);

~~~
LefterisJP
nice idea!

