1

I created a basic C project in Xcode and modified the starter code in main.c slightly. I also went into the build settings and told it to use ANSI-C. Here's the code I have:

int main(int argc, const char * argv[])
{
    // a statement!
    printf("Hello, World!\n");

    // shouldn't this cause a compiler error?
    // the variable isn't declared at the top of the scope.
    int x;
    x += 10;

    return 0;
}

Obviously, it doesn't do much, but I expected the variable declaration to produce a compiler error (since older versions of C require variable declarations at the beginning of the scope, before other statements). However, Xcode happily compiles it and runs it with neither an error or warning.

I might be making a dumb mistake somewhere, but I'm trying to understand why this code compiles. I've read that C99 and C11 allow you to declare variables anywhere, so this would work, but I explicitly set the project to use ANSI-C. Is this just the way Apple's LLVM compiler works? Or am I missing something elsewhere?

kromenak
  • 479
  • 5
  • 13
  • 2
    What compilation options did you actually set? Unless you set `-std=c90` or `-ansi`, you will get C99 or C11 by default. Don't forget, the C99 standard compilers are the old ones; the C90 standard compilers are archaic (25+ years old), dating from an era when the internet (or, at least, things like the HTTP protocol) barely existed. – Jonathan Leffler Jan 02 '16 at 00:44
  • @JonathanLeffler ANSI C is still the most portable variant of C—many exotic platforms (DSPs and the like) only have C89 compilers provided. Even Microsoft does not provide a C99 compiler. – fuz Jan 02 '16 at 00:47
  • @FUZxxl: you don't have to tell me about MS; it is one of the banes of my life that I can't use the facilities of C99 because MS doesn't support in the compilers that they provide and that the project I work on chooses to use (older versions of their compiler; the latest versions have support for the bits of C99 I want to use, but glaciers move faster than our build processes change). – Jonathan Leffler Jan 02 '16 at 00:49
  • Yeah, I'm not against using the newer standards like C99, though I do like the portability benefits of something like ANSI. For this question, I'm mainly curious why this C code compiles despite my clearly violating a compilation rule. Is it an issue with how Xcode handles C code, or am I misunderstanding something? In the Xcode build settings, I set the "C Language Dialect" to ANSI-C. If I look at the command line build command, it does indeed have the -ansi argument set. – kromenak Jan 02 '16 at 00:55
  • @kromenak: ANSI is a national standard, so not very portable by definition. And C99 is no already over 16 years old, the current (and only!) C standard is C11. You really should not use a >25 year old coding standard if you are not forced with a gun (or with getting fired). This actively defies modern coding techniques. – too honest for this site Jan 02 '16 at 08:36
  • @Olaf, I didn't realize that about ANSI, thanks for the insight! I'm perfectly happy using C11 - I was mainly curious why telling the compiler to use ANSI didn't cause the variable warning to occur. Many C tutorials I've found note that variables must be at the beginning of the scope, which is clearly not really the case anymore unless you use very specific compiler settings. I'm fine with that overall, since putting all the variables at the beginning hurts readability, in my opinion. – kromenak Jan 03 '16 at 20:29
  • @kromenak: To be pedantic: AFAIK the ANSI - like many other national stadnardisation organisations, e.g. German DIN - automatically adapt ISO standards. So it is very likely C11 are also ANSI standards. Thus the term "ANSI-C" is a bit missleading. More correct and unambiguous is to refer to C90 (technically identical to C89), C99 and C11. – too honest for this site Jan 03 '16 at 20:48

1 Answers1

4

TL;DR You need to add -pedantic (or -Wdeclaration-after-statement) to -ansi to get the warning you want.

Somewhat to my surprise, both clang (from Apple XCode 7.2) and gcc (from GCC 5.3.0, which I built), accept the code when compiled with either -std=c90 or -ansi even though it is not strictly compliant with C90.

However, both complain when told to be -pedantic.

$ clang -ansi -c xyz.c
$ clang -std=c90 -c xyz.c
$ gcc -std=c90 -c xyz.c
$ which gcc
/opt/gcc/v5.3.0/bin/gcc
$ gcc -std=c90 -pedantic -c xyz.c
xyz.c: In function ‘main’:
xyz.c:7:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
     int x;
     ^
$ clang -pedantic -std=c90 -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
    int x;
        ^
1 warning generated.
$ clang -pedantic -ansi -c xyz.c
xyz.c:7:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
    int x;
        ^
1 warning generated.
$

The file xyz.c is your source code with the comments stripped, #include <stdio.h> added at the top, and int main(void) in place of int main(int argc, char **argv) since the code doesn't use the arguments.

Note that your code has undefined behaviour; incrementing an uninitialized variable is a bad idea.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Ah, that does it! Interesting it just shows up as a warning, but I guess if it can compile, it might as well, and then the warning is handy info to have. Also, thanks for the variable note - will keep that in mind. I also totally forgot that the "//" style comment isn't allowed in ANSI C - was kind of surprised when I added "-pedantic" and suddenly the auto-generated Xcode file comment was generating a warning :P. – kromenak Jan 02 '16 at 01:24
  • If you want the warnings to be errors, use `-Werror` too; I use that all the time. Add `-Wall` while you're at it, and `-Wextra`. Actually, I use: `gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror` routinely as my basic "It doesn't count unless it compiles cleanly under these flags" operating mode (which is the sort of reason I added `#include ` and removed `argc` and `argv`). You'd change `-std=c11` to `-std=c90 -pedantic`. – Jonathan Leffler Jan 02 '16 at 01:27