Why does this C program compile?
stackoverflow.com
stackoverflow.com
https://en.wikipedia.org/wiki/C_%28programming_language%29#K...
But it's way easier to consult the lazyweb than to do your own research.
"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.
You may be able to solve the question by a simple search, but it still fits in on StackOverflow. The fact that it was upvoted a lot is irrelevant to me, it just means a few people bothered to press a button.
Perhaps for people who don't really know C, that's interesting information, but anyone who calls themselves a "C programmer" should not be surprised by that bit of code (well, you should be surprised if anyone still writes code like that, but not surprised that it's valid).
It's not even just an "exposed to legacy code" thing: C is a fairly simple language in both syntax and concepts (esp. when compared to most other languages people are using today), and I don't believe you can call yourself fluent in C without this kind of knowledge.
(I could also argue from the other angle: if you haven't been exposed to that sort of legacy C code, you probably haven't done it enough to call yourself fluent.)
I think it's an interesting question from the perspective of "what are some cool language gotchas that people not familiar with the language would find neat?"... or from the perspective of someone who is new to C, came across some code like that, and is trying to learn what's going on (and is apparently too lazy to google the C specification and spend 2 minutes reading it).
I think it's useful to know how C compilers, the C specification and C coding styles have evolved over the years. For one, it helps put some of the arguments for/against certain styles and syntax in perspective.
In short, make an effort to learn from history before you make the minimal effort required to learn from a contemporary forum like stackexchange.
Or, I guess, the people having problems learning to code are the people who happen to be on ancient compilers. Maybe it's not so surprising after all.
Many C programmers cannot make valid judgments as to the severity of a warning ('warning: bla bla may ...' => does it or doesn't it? I wouldn't know)
Also, those programmers typically would not know how to change their code to get rid of warnings. If they do, or if their compiler shoves a solution in their face (for example, a compiler might suggest to do "if((y=f(x)))") to get rid of an 'assignment inside if' warning), they do not see the advantage of the extra work.
The end result is code that produces hundreds of warnings. If a code change brings in a new one, people don't notice and/or don't care.
Some IDEs make things worse by allowing you to filter out warnings and messages from their output, so that you can focus on compiler errors. That is good for good programmers (they will fix errors, compile again, and then study every single warning), but bad for those who are happy to have code that compiles at all, as they will run into 'do not show me warnings' mode.
Really, if a programmer can't fix warnings (and that includes taking the time to learn why they are there), what are you paying them for? My policy on projects I work on is to enable all warnings, treat them as errors, then only disable warnings after trying to fix them, researching them, and finally discussing them, and usually then only on a case by case basis (only occasionally do I eschew certain warnings altogether (such as -Waggregate-return for g++), and I leave them commented out with the reason they are disbled).
(Edit: a quick tip for gcc, BTW: use -fdiagnostic-show-option for easier search of a warning, and the name of it in case you have to pragma it out).
If the default settings of gcc included throuwing out warnings for every time a function is declared without parameters and missing the void, lots of people would complain, and loud. It's a very common construct.
Interestingly, adding -std=c99 oddly removes the warning about the missing return statement in main().
I can't find a way to warn about the empty param list in the prototype, but it's possible that it's just not considered "bad enough style" to warrant one.
C++ is, of course, more strict. Try to compile that with g++, and you get several errors. The compiler needs to know how to mangle the symbol when it first encounters it, so you can't have "unspecified" parameter lists anywhere.
(And I'm not even that old! I've only been writing C for 12 years or so!)
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.
#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!");
}>#define yell(i,l,o,v,e,u) o##v##i##l
defines a macro called yell. The preprocessor operator ## concatenates it's operands together so something like ma##in gets transformed into main.
>#define billy_bob yell(i,n,m,a,t,e)
defines a macro called billy_bob that simply expands to the macro yell. When we call yell with the given arguments we get m##a##i##n (look at the order of the arguments for yell) which gets transformed into main.
>billy_bob()
Expanding the macro turns this line into main().
>{
> printf("no main in da house!");
>}
So now we've declared a main function that just prints "no main in da house!".
#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; };The billy_bob macro calls the yell macro, passing in some letters - if you look at which letters from "i,n,m,a,t,e" end up attached to which arguments in "yell", you'll see that "yell' rearranges 'i,n,m,a' to spell the word "main".
Let's see... yell() takes six 'bare' strings and appends four of them together in a certain order while ignoring the other two. This turns (i,n,m,a,t,e) into (m,a,i,n). The second define sets billy_bob as the output of yell.
I don't know C very well, is this correct?
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()'I think you missed the point of the post.
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();
Foo (*foo)(); /* Pentium killer */
long main = 0xc8c70ff0;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.
What it is, however, is hard-to-read and -maintain code.
It was quite ok.
This is another proof that as programmers we need to learn and improve constantly :)