7

I was just wondering about the content of question 'Hello, World!' in C without semicolons and without 'if', 'while', or 'for' statements.

The following code worked in C, but not in C++:

int main(int argc, char *argv[printf("Hello, World!\n")]) {}

In C++, I get this error:

error: expected ‘,’ or ‘...’ before ‘argv’|
warning: second argument of ‘int main(int, char*)’ should be ‘char **’ [-Wmain]|
||=== Build finished: 1 errors, 1 warnings ===|

Why is it not working in C++?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Forever Learner
  • 1,465
  • 4
  • 15
  • 30
  • @CarlNorum: That's not really the crux of it. In fact, the OP is trying to give it a `char**` (at least once the array decays), but a parsing error means the compiler is misinterpreting. – Lightness Races in Orbit Jan 04 '12 at 18:54
  • That's true, now that I look at it again. Hooray for VLAs! =) – Carl Norum Jan 04 '12 at 18:55
  • What's your compiler version? And are you sure you copied the code properly? I can't reproduce this at all. – Lightness Races in Orbit Jan 04 '12 at 19:02
  • @Lightness Races in Orbit: Yes I copied the code correctly. I am using codblocks IDE 10.05. When I ran gcc -v on Ubuntu terminal I got the version :gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) – Forever Learner Jan 04 '12 at 19:12
  • @LightnessRacesinOrbit: Certainly with GCC, it [works in C](http://ideone.com/THi07), but [not in C++](http://ideone.com/fFse8) – Mike Seymour Jan 04 '12 at 19:14
  • @CppLearner: OK; I've reproduced it in GCC 4.5.1 too now, so I guess it's a parse confusion recently introduced. Ultimately, I guess, there's no "right" way to parse this invalid code. – Lightness Races in Orbit Jan 04 '12 at 19:14
  • @MikeSeymour: I'm trying to rationalise about _specific_ versions of GCC, as to this _specific_ error message. I concede that my earlier comment was unclear in that regard. – Lightness Races in Orbit Jan 04 '12 at 19:14

3 Answers3

19

Because C++ doesn't have any variable-length array feature.

The argv parameter in

char *argv[printf("Hello, World!\n")]

is a variable-length array.

The expression that specify the size of the array is

printf("Hello, World!\n")

The result of this expression is of type int and is the number of characters transmitted (or a negative value if there is an error).

An array where the expression in the [] is not constant, like in the example the printf expression, is a variable-length array. Those arrays also are permitted to be used as the type of a function parameter.

A variable-length array is a feature introduced in C in C99 and has not been introduced in C++.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ouah
  • 142,963
  • 15
  • 272
  • 331
  • 5
    Can you expand on this answer? It's quite incomplete for a score of seven. – Lightness Races in Orbit Jan 04 '12 at 19:03
  • @LightnessRacesinOrbit ok, I'm doing it – ouah Jan 04 '12 at 19:06
  • Does C have a variable array feature?? It's a wonder that this actually compiles in C, and I don't think it's standard. – ugoren Jan 04 '12 at 19:24
  • @ugoren: C99 does. C89/C90 do not. GCC does support them in C++ as an extension; whether or not that would allow this bizarre code to compile I couldn't say. Anyway, I'm tempted to suggest that this is either a loophole in C's VLAs, or a loophole in GCC's implementation, but I couldn't say for sure. – Lightness Races in Orbit Jan 04 '12 at 19:26
8

As the error message indicates, main expects char** for its second argument. However, due to array decay rules, the following are both OK:

int main(int argc, char** argv);   // OK
int main(int argc, char* argv[]);  // OK

And, in fact, the following is also equivalent because array decay doesn't care about dimensions:

int main(int argc, char* argv[5]); // OK

However, whereas in C99 arrays may have variable length, this is not the case in C++. So using a non-constant expression for that array dimension — in your case, printf("Hello world\n") — is invalid syntax.

int main(int argc, char* argv[printf("Hello, world!\n")]); // Not OK!

This invalid syntax is confusing the parser and causing this misleading error in your compiler.

If you simplify the code slightly to remove the function-call-expression (but still using a non-constant for array bounds) then you get a far more relevant error message:

int x = 5;
int main(int argc, char* argv[x]) {}
// error: array bound is not an integer constant

Actually, GCC 4.1.2 gives this useful message for your original code, too, so your compiler must be really old... either that or your testcase is broken despite the far newer GCC 4.5.1 yielding the message you posted.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • @Keith: Thanks; suppose that's better. Nuked my latest changes, though! – Lightness Races in Orbit Jan 04 '12 at 19:05
  • Whoops, didn't mean to do that. I got notice that it had been edited, but I canceled my edit and did it again. I guess we still managed to collide. – Keith Thompson Jan 04 '12 at 19:08
  • 1
    "Array decay rules" would usually refer to the decay/conversion of an array expression to a pointer to its first element ([C99](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) 6.3.2.1p3). This is a distinct rule applying to parameter declarations, described by the standard as an adjustment rather than a conversion (C99 6.7.5.3p7). – Keith Thompson Jan 04 '12 at 19:15
  • @Keith: C++ citations please! I'll be happy to change that terminology though; I basically just made it up ^_^ – Lightness Races in Orbit Jan 04 '12 at 19:16
  • Neither standard uses the word "decay" for this, but I've most often seen it used to refer to the implicit array-to-pointer conversion; see, for example, question 6.3 of the [comp.lang.c FAQ](http://c-faq.com). N3290 (the closest thing I have to the C++11 standard) 4.2 [conv.array] says that the conversion *can* happen; 5p8 [expr] says when it's done implicitly. The parameter adjustment rule is in 8.3.5p5 [dcl.fct]. – Keith Thompson Jan 04 '12 at 19:30
  • @Keith: Then I guess I made up a non-normative term :) – Lightness Races in Orbit Jan 04 '12 at 19:33
  • @KeithThompson *decay* is also used in Peter van der Linden "Expert C Programming" book, but I agree with you the correct word is *conversion* – ouah Jan 04 '12 at 19:50
  • Dentists use it sometimes too, so there's precedence. – Lightness Races in Orbit Jan 04 '12 at 19:54
3

In C, char *argv[some_expression] is a variable-length array, and so when used as a function argument is interpreted as meaning a pointer (just as a fixed-length or unknown-length array does when declaring a function argument).

In C++, variable-length arrays do not exist, so it's not valid. char * argv[some_constant] and char * argv[], are both valid, and equivalent to char ** argv - but of course none of these can have side effects, and so can't be used to solve that silly exercise.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644