

Why does this C program compile? - manojlds
http://stackoverflow.com/q/13950642/526535

======
jbuzbee
Guess I grew up with old-school C. Looking at the question with example code
made me think: "Am I missing something? Looks like pretty ordinary C to me.
Why wouldn't it compile?"

~~~
minimax
If you were a programmer in the days before C had prototypes then you are
definitely from the old school. If you're working on code that still looks
like this in 2012 then maybe it's time to brush up on modern C. ;-)

~~~
hnriot
He didn't say he still works on code like this, but like me, this program is
obviously fine, there's no point in asking why it works because c is backward
compatible and it's pretty clear to anyone who knows c that this will work. It
doesn't mean we'd write code like that...

~~~
asveikau
This is what bothers me about a lot of programmer communities these days. What
is a very mundane detail of K&R legacy, that C programmers know very well
either from looking at old source trees or making sense of error messages,
suddenly turns into something where 116 people (current stack overflow +1
count) are totally amazed and breathless that they've discovered something
deep. I suppose it's fair if they just don't know C, so they've not seen it
and find it interesting, but could this person's dilemma not be resolved with
a simple google search? Or even taking a guess?

~~~
Retric
It can be really hard to Google things when you don't know the terms involved.
Until, someone posts source code and you get directed to stack overflow etc.
Thus, the fact that out of millions of people with some familiarity with C 100
or 1000 chose to up vote an obvious post does not really seem that strange.

~~~
kelnos
Thing is, the C standard (compared to many other standards) isn't even that
complicated. Googling for the C standard doc, and then grepping through for
"function declaration" would likely clear that up.

But it's way easier to consult the lazyweb than to do your own research.

~~~
Retric
Searching for "C standard doc" does not actually work.

"C99 standard doc" let's you find <http://www.open-
std.org/jtc1/sc22/wg14/www/docs/n1124.pdf> but searching for "function
declaration" does not take you anywhere useful.

That's not to say reading the whole thing is a waste of time, just beyond the
scope of most new programmers.

------
bitwize
An empty parameter list in a C prototype means "parameters are unspecified".

In C++ it means no parameters.

To declare a C function parameterless you need to say int func(void).

Also, C will assume int if you leave off param or return types.

...I'm surprised I know that.

------
jfaucett
this is pretty basic, I would hope no actual c programmers would ask this
question. Compilers are fun aren't they, how bout this one:

    
    
      #include <stdio.h>
      #define yell(i,l,o,v,e,u) o##v##i##l
      #define billy_bob yell(i,n,m,a,t,e)
    
      billy_bob() 
      {
        printf("no main in da house!");
      }

~~~
ntumlin
Would you please explain the code?

~~~
cnvogel
There's the "##" operator with which you can glue together identifiers with
the preprocessor.

    
    
      #define yell(i,l,o,v,e,u) o##v##i##l
      yell(i,l,o,v,e,u) will turn into the identifier ovil.
    

And billy_bot just uses the yell-macro to produce a "main" identifier.

    
    
      #define billy_bob yell(i,n,m,a,t,e)
    
      yell(i,l,o,v,e,u) --> o ## v ## i ## l
      yell(i,n,m,a,t,e) --> m ## a ## i ## n
    

So billy_bop is main.

Why is this features useful at all? When you actually want to programmatically
create function names, type names, struct names in preprocessor generated
code.

    
    
         #define ENCAPS_STRUCT(type,name)  struct encaps_##type { type name; }
         ENCAPS_STRUCT(int,a);
    

will generate...

    
    
         $ cc -E test.c
         # 1 "test.c"
         # 1 "<built-in>"
         # 1 "<command-line>"
         # 1 "test.c"
    
         struct encaps_int { int a; };

------
Yoni1
This is kind of an encouraging question. To me it screams "people don't know C
anymore, capitalize on your skill while you still can".

------
minimax
C++ programmers will be familiar with a related (and probably more
commonplace) problem:

    
    
      struct Foo {int a;};
    
      int main(int argc, char **argv) {
          Foo foo();
          foo.a = 42;
          return 0;
      }
    

Looks ok, right? Wrong.

    
    
      error: request for member 'a' in 'foo', which is of non-class type 'Foo()'

~~~
cube13
foo()-with the parenthesis- is a function. foo-without the parenthesis-is a
variable. That means that:

    
    
      Foo foo();
    

is a function pointer declaration within the scope of the main function. Since
it's a function, which does not have member types, a is not within the scope
of Foo().

Now, if there was a 0 argument constructor for struct Foo, this would be
valid:

Foo foo = Foo();

~~~
kelnos
Function declaration, not function _pointer_ declaration. The latter would be

    
    
        Foo (*foo)();

------
spudlyo

        /* Pentium killer */
        long main = 0xc8c70ff0;

------
TeMPOraL
That's why I always tell people that gcc is mostly useless without _\--ansi
--pedantic -Wall_.

------
bjoe_lewis
Is it a bad code, or otherwise?

~~~
johnbellone
I would say that it is ambiguous code.

The first C project that I worked on used this a lot. Its definitely not the
easiest to understand when coming from a C++ background (because no parameter
declaration means no parameters) or from other descendant languages.

~~~
kelnos
It's actually not ambiguous code at all. It's perfectly well-formed and
unambiguous with respect to the C standard.

What it is, however, is hard-to-read and -maintain code.

