3

I have below discovery by chance. The compiler compiles the below code without any error or warning. Please help me understand why the compiler is not throwing any error? The program contains just a string in a double quotation.

I have not declared any char array neither assigned the below string to any variable.

void main()
{
    "Why there is no error in compilation?";
}
pkthapa
  • 1,029
  • 1
  • 17
  • 27

4 Answers4

10

Because any expression is a valid statement.

"Why is there no error in compilation?";

is a statement that consists of an expression that evaluates to the given literal string. This is a perfectly valid statement that happens to have no effect whatsoever.

J Earls
  • 1,792
  • 8
  • 12
  • No. Because it is undefined behaviour. – 4pie0 Sep 03 '16 at 17:58
  • It is not undefined behaviour. It is precisely defined. The expression (which consists of a string literal) is evaluated, and the results of the expression are discarded. – J Earls Sep 03 '16 at 18:01
  • 1
    The statement is not undefined behavior. The declaration of `void main`, is. – Thomas Matthews Sep 03 '16 at 18:02
  • @ThomasMatthews that may be the case, but that's not the question OP was asking. – J Earls Sep 03 '16 at 18:03
  • A string literal or any other expression is not a statement, but - well - an expression. What makes an expression a statement is the semicolon. So your line is **not** a statement. – too honest for this site Sep 03 '16 at 18:06
  • @JEarls It is undefined behaviour. It doesn't matter what happens after UB happened and it has happened before statement, so it is meaningless whether statement itself is fine or not. This code may work also if statement is pure garbage. – 4pie0 Sep 03 '16 at 18:13
  • @where_is_tftp The fact that `void main()` is "undefined behaviour" (which is actually not "undefined" until the *return* from main, if even then depending on the implementation) does not change the fact that the OP was asking about why there was no compiler error on a string literal being used as a statement. – J Earls Sep 03 '16 at 18:22
  • 1
    Strictly speaking, @where_is_tftp is correct. Once you invoke UB, everything is lost already. From wrong code anything can follow. And still, you don't have a statement in your code. – too honest for this site Sep 03 '16 at 19:34
  • @Olaf I was describing the *expression* that the OP included. I have edited my question to show the expression as a statement. – J Earls Sep 03 '16 at 19:39
  • @Olaf, only that this isn't UB, because `void` is permitted in a freestanding environment. – Jens Gustedt Sep 03 '16 at 19:39
  • @JensGustedt: See my comment to the deleted answer of where_is_tftp. Yes, I should have added "if OP uses a hosted environment" or a freestanding with a different signature for `main` or a different entry function. – too honest for this site Sep 03 '16 at 19:43
  • Defining `void main()` does not inherently have undefined behavior. For a conforming hosted implementation, `main` is defined as `int main(void)`, `int main(int argc, char *argv[])` or equivalent, "*or in some other implementation-defined manner*" ([N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 5.1.2.2.1). If the implementation documents that it accepts `void main(void)`, then `void main(void)` is valid *for that implementation*. – Keith Thompson Sep 03 '16 at 20:13
1

Of course, "useful" statements look more like

a = b;

But well;

b;

is also a valid statement. In your case, b is simply string literal; and you are free to place that within a the body of a method. Obviously this statement doesn't have any side effects; but what if the statement would be something like

"some string " + someFunctionReturningString();

You probably would want that expression to be executed; and as side effect, that method to be called, wouldn't you?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
1

Compile the program with -Wunused-value flag. It just raises

warning: statement with no effect "Why there is no error in compilation?"; ^

That is it.

And If you compile the above code with -Wall flag it also says

warning: return type of ‘main’ is not ‘int’ [-Wmain] void main() {

Parnab Sanyal
  • 749
  • 5
  • 19
  • Those flags are specific to gcc (and compilers that support its options). And this doesn't really answer the question. A conforming C compiler is not required to issue any diagnostic for the code in the question. – Keith Thompson Sep 03 '16 at 20:38
  • He said that **The compiler compiles the below code without any error or warning**. That is why I mentioned those flags. And Yes you are correct. I should have asked him whether he uses `gcc` or any other compiler. @KeithThompson – Parnab Sanyal Sep 03 '16 at 20:54
  • You explained how to make the compiler complain. That's certainly useful information, but the question was why the compiler doesn't complain in the first place. – Keith Thompson Sep 03 '16 at 21:09
1
void main()
{
    "Why there is no error in compilation?";
}

First, let's address the string literal. An expression statement, which is valid in any context where any statement is valid, consists of an (optional) expression followed by a semicolon. The expression is evaluated and any result is discarded. (The empty statement, consisting of just a semicolon, is classified as an expression statement; I'm not sure why.)

Expression statements are very common, but usually used when the expression has side effects. For example, both assignments (x = 42;) and function calls (printf("Hello, world\n")) are expressions, and the both yield values. If you don't care about the result, just add a semicolon and you have a valid statement.

Not all expressions have side effects. Adding a semicolon to an expression that doesn't have any side effects, as you've done here (a string literal is an expression), is not generally useful, but the language doesn't forbid it. Generally C lets you do what you want and lets you worry about whether it makes sense, rather than imposing special-case rules that might prevent mistakes but could also prevent you from doing something useful.


Now let's cover void main(). A lot of people will tell you, with some justification, that this is wrong, and that the correct definition is int main(void). That's almost correct, and it's excellent advice, but the details are more complicated than that.

For a hosted implementation (basically one that provides the standard library), main may be defined in one of three ways:

int main(void) { /* ... */ }

or

int main(int argc, char *argv[]) { /* ... */ }

or equivalent, "or in some other implementation-defined manner." (See N1570 section 5.1.2.2.2 for the gory details.) That means that a particular implementation is permitted to document and implement forms of main other than the two mandated forms. In particular, a compiler can (and some do) state in its documentation that

void main() { /* ... */ }

and/or

void main(void) { /* ... */ }

is valid for that compiler. And a compiler that doesn't explicitly support void main() isn't required to complain if you write void main() anyway. It's not a syntax error or a constraint violation; it just has undefined behavior.

For a freestanding implementation (basically one that targets embedded systems with no OS, and no requirement to support most of the standard library), the entry point is entirely implementation-defined; it needn't even be called main. Requiring void main() is not uncommon for such implementations. (You're probably using a hosted implementation.)

Having said all that, if you're using a hosted implementation, you should always define main with an int return type (and in C you should int main(void) rather than int main()). There is no good reason to use void main(). It makes your program non-portable, and it causes annoying pedants like me to bore you with lengthy discussions of how main should be defined.

A number of C books advise you to use void main(). If you see this, remember who wrote the book and avoid anything written by that author; he or she doesn't know C very well, and will likely make other mistakes. (I'm thinking of Herbert Schildt in particular.) The great irony here is that void keyword was introduced by the 1989 ANSI C standard -- the very same standard that introduced the requirement for main to return int (unless the implementation explicitly permits something else).


I've discussed the C rules so far. Your question is tagged both C and C++, and the rules are a bit different in C++. In C++, empty parentheses on a function declaration or definition have a different meaning, and you should write int main() rather than int main(void) (the latter is supported in C++, but only for compatibility with C). And C++ requires main to return int for hosted implementations, with no permission for an implementation to support void main().

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631