4

I'm reading an introducty book about C and I came across the following paragraph:

enter image description here

But the following code compiles with expected output:

#include <stdio.h>

int main()
{
    for(int i = 0; i<=10; i++)
    {
        int val = i + 1;
        
        int x = val * val;
        
        printf("%d\n", x);

        int y = x;

    }

    return 0;
}

I use https://www.onlinegdb.com/ and in the above code I declared many variables after the first executable statement. And this is to me does not match what the section from the book tells.

Am I misunderstanding what the book is telling?

GNZ
  • 575
  • 2
  • 10
  • You targeting C89 or C99? – genpfault Dec 02 '22 at 21:48
  • you are not misunderstanding what the book says. It's just that the book is probably really really old. I might be wrong, but that was true for pre standard C. – bolov Dec 02 '22 at 21:48
  • 9
    No. The book is just wrong. Or 20+ years out of date, at least. – John Bollinger Dec 02 '22 at 21:48
  • The book I read is published in 2019. – GNZ Dec 02 '22 at 21:49
  • 2
    Published in 2019 but probably written before 1999. What edition is it? – Tibrogargan Dec 02 '22 at 21:51
  • 2
    In **each block** of your example, there are no non-declaration statements before each declaration. – Davis Herring Dec 02 '22 at 21:51
  • @DavisHerring onlinegdb doesn't care when you declare variables as long as you don't use them before they are declared. – Tibrogargan Dec 02 '22 at 21:53
  • 11
    The statement in the book was true of C90, also known as "ANSI C". That restriction was lifted in the next revision of the language specification, C99, published in 1999. Since then there have been C11 and C17, and soon there will be C23, so the information you're asking about is dreadfully dated. I would take this as a sign that maybe you want to learn C from a different book. – John Bollinger Dec 02 '22 at 21:53
  • @Tibrogargan Correct the first edition was in 2013. Latest one I have is from2019. – GNZ Dec 02 '22 at 21:53
  • 2
    There's probably a disclaimer somewhere in there that says the book is referring to ANSI C unless otherwise specified – Tibrogargan Dec 02 '22 at 21:55
  • It says it follows C90 and compiles example's with -std=gnu90 command https://www.amazon.co.uk/Java-C-Primer-Charlie-McDowell/dp/8750210440 – GNZ Dec 02 '22 at 21:57
  • 3
    _It says it follows C90_ So, you've just confirmed that it was _obsolete_ when it was written in 2013 (because C99 was around 14 years before) and the author was too lazy to revise it for the 2019 edition (6 years later). Try a better book: [The Definitive C Book Guide and List](https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list) Personally, I still prefer Kernighan and Ritchie's original book. – Craig Estey Dec 02 '22 at 22:05
  • cppreference.com is a good reference guide for C and C++. For updated information, I'd refer to that site. – Ty Q. Dec 02 '22 at 22:10
  • @Tibrogargan: Of course, because of the rules in newer versions. I was pointing out that the example given didn’t demonstrate any contravention of the rule given. – Davis Herring Dec 03 '22 at 04:54
  • Now it makes more sense I added int y = x; after printf. – GNZ Dec 03 '22 at 15:13

3 Answers3

7

In strictly conforming C 1990, declarations could appear only at file scope (outside of function definitions) or at the start of a compound statement. The grammar for a compound statement in C 1990 6.6.2 was:

compound-statement
    { declaration-listopt statement-listopt }

That says a compound statement is { followed by zero or more declarations, then zero or more statements, then }. So the declarations had to come first.

In C 1999 6.8.2, this changed to:

compound-statement
    { block-item-listopt }

A block-item-list is a list of block-item, each of which may be a declaration or a statement, so declarations and statements could be freely mixed.

In your example, the declarations int val = i + 1; and int x = val * val; do not appear after executable statements in their compound statement. The compound statement starts with the { immediately before int val = i + 1;, so that declaration is at the start of the compound statement.

Another change was that the for grammar was changed from this in C 1990 6.6.5:

for ( expressionopt ; expressionopt ; expressionopt ) statement

to this choice of two forms in C 1999 6.8.5:

for ( expressionopt ; expressionopt ; expressionopt ) statement
for ( declaration expressionopt ; expressionopt ) statement

(Note the declaration includes a terminating ;.)

That explains why you can have int i = 0 in for(int i = 0; i<=10; i++).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • it might be work mentioning that gcc allows it without the `-pedantic` flag – bolov Dec 02 '22 at 22:07
  • *"the first `;` in that second line was missing in the document"* Actually I believe that was intentional, as the syntax for *declaration* includes the `;` at the end. This syntax also exists in C17. – dbush Dec 02 '22 at 22:37
1

The book is referring to the original C specification from over 30 years ago known as "ANSI C" or "C89" or "C90". If we run a C compiler in C89 mode, -std=c89, we get a warning from your code...

cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c89 -pedantic -g -fsanitize=address   -c -o test.o test.c
test.c:5:9: warning: variable declaration in for loop is a C99-specific feature [-Wc99-extensions]
    for(int i = 0; i<=10; i++)
        ^
test.c:5:9: warning: GCC does not allow variable declarations in for loop initializers before C99 [-Wgcc-compat]
2 warnings generated.

C99, the update to C made in 1999, made this untrue. Running your code with -std=c99 gives no warning. C99 made this and other impactful changes to the language, like // comments.

There is also C11 and the latest stable version of C is C17, but compiler support for both is spotty.


Why is this book referring to such an old version of the language? C has existed since 1978 and there are a lot of old code and old compilers out there. C Compilers have been very slow to fully adopt new standards making authors quite conservative. A big stumbling block was Microsoft Visual C++ did not implement C99 until 2013! So ANSI C was the lowest-common denominator for a very long time.

In recent years, C compilers have gotten better about standards compliance, so you can rely on C99 (which is old enough to drink) as your baseline.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • Interesting. Could you try to declare some int y right after printf and compile with -std=c89 ? Im very curious about the warning. Thanks – GNZ Dec 02 '22 at 22:52
  • @GNZ `test.c:13:13: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]` – Schwern Dec 03 '22 at 00:01
0

All variables in your example have been declared before used.

The declarations are:

int i ...;
int val ...;
int x ...;

Note that all declarations happen before the first function call in the corresponding block. On other words: i, val and x are all declared before the printf.

As stated in the comments: Some old books might refer to old versions of C. The variable declaration within the for loop came with C99 for example. Beginning with C99 you could also declare variables in the middle of the block. So you are allowed to declare some int y; after the printf and your code would still compile.