3

I was wondering what would happen if I left out the parameter declarations in a K&R function definition, so I tried the following:

#include <stdio.h>

void f(a) 
// int a;       <--- omitting `declaration-list` causes warning in gcc, but nothing in clang
{
    printf("%d", 9);
}

int main() 
{
    f(9);
    return 0;
}

When I compile this with gcc 11, a diagnostic is issued in the form of a warning (i.e. warning: type of 'a' defaults to 'int'). However, when I compile it with clang 14, no diagnostic message is issued.

This confused me because in the Standard, omitting the declaration-list (which contains the parameter declarations) is a constraint violation (as per C11 6.9.1(6)), which requires a conforming implementation to issue a diagnostic (as per C11 5.1.1.3). So, why didn't clang issue a warning? Have I misinterpreted something?


EDIT: Must a diagnostic be issued if a constraint violation can be "fixed" by the compiler applying some other provision in the Standard?

For example, the empty declaration list in the code above has always been a constraint violation (since C89). However, prior to C99, the Standard also had an implicit int rule (see C90 6.5.2), which would have allowed the compiler to assume any undeclared parameters as being of type int and thereby recover from the no-empty-declaration-list constraint violation.

So, would a pre-1999 ANSI-conformant compiler have still issued a diagnostic in this case? My first impression was that it would have since the constraint would have taken precedence over the implicit int rule, but pg. 287 of Harbison and Steele says (emphasis added):

In the pre-Standard traditional form, the parameter names are listed in the declarator and the types are specified (in any order) in the declaration-list opt following the declarator. All parameters should be declared in the declaration-list, but prior to C99 omitted parameter declarations defaulted to type int.

The bit in bold makes it seem like empty declaration lists were allowed since the implicit int rule would have "fixed" any no-empty-declaration-list constraint violations.

user51462
  • 1,658
  • 2
  • 13
  • 41
  • 2
    With a late enough Clang I actually get an [*error*](https://godbolt.org/z/9eYTvaW5G). *And* a warning. – Some programmer dude Dec 03 '22 at 04:05
  • 1
    Before considering whether a piece of software should do something, you should consider whether there is a reason it should do something. Have you ever seen a statement that says Clang, when used with default switches, conforms to the C standard? Or did you just assume that because Clang is a C compiler that it is a standard C compiler? – Eric Postpischil Dec 03 '22 at 11:10
  • @EricPostpischil, the latter - I just assumed because I figured conformance with the standard would be the *default* mode, instead of something one has to turn on explicitly. Is this not the case? – user51462 Dec 03 '22 at 11:37
  • 5
    @user51462: No, both GCC and Clang default to a mode in which the compiler uses certain customizations to the C language rather than the C standard. To improve conformance to the standard, you can use `-std=c18 -pedantic`. – Eric Postpischil Dec 03 '22 at 11:51
  • (GCC and Clang and MSVC and other compilers are written by various people doing their own things, working for employers with business goals or contributing to projects for their own motivations, while the C committee is another group of people [possibly with some overlap] writing a document and saying “Hey, wouldn’t it be nice if everybody did it this way?” There is no legal or other authoritative requirement that the first people listen to the second group. Nobody owns the “C” trademark; everybody can do what they want with it. The “C standard” is just one choice of what C is or can be.) – Eric Postpischil Dec 03 '22 at 11:56
  • @EricPostpischil, I thought `-std=c18` would error for the code in my question since the implicit `int` rule was removed in C99, but it just issues a warning when used with `-pedantic`. I have to use `-pedantic-errors` to get it to error. And it doesn't even complain about the K&R syntax, arrrgghh! Lol, thanks for your patience all the same :) – user51462 Dec 03 '22 at 12:37
  • @user51462 May be somehow useful (taken from [C2x Charter](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2086.htm)): "On the other hand, no one implementation was held up as the exemplar by which to define C: It is assumed that all existing implementations must change somewhat to conform to the Standard." – pmor Jan 12 '23 at 15:04

2 Answers2

3

clang will generate a warning if compiled with the -pedantic flag.

<source>:3:8: warning: parameter 'a' was not declared, defaulting to type 'int' [-Wpedantic]
void f(a) 
       ^
1 warning generated.
ASM generation compiler returned: 0
<source>:3:8: warning: parameter 'a' was not declared, defaulting to type 'int' [-Wpedantic]
void f(a) 
       ^
1 warning generated.
Execution build compiler returned: 0
Program returned: 0
9

https://godbolt.org/z/e73M1Eq8E

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thanks @dbush. I'm not quite sure what clang's `-pedantic` does - the [documentation](https://clang.llvm.org/docs/UsersManual.html) says it "warns on language extensions", but the constraint in C11 6.9.1(6) was present in C89 too (see [here](https://web.archive.org/web/20200909074736if_/https://www.pdf-archive.com/2014/10/02/ansi-iso-9899-1990-1/ansi-iso-9899-1990-1.pdf)). – user51462 Dec 03 '22 at 04:49
  • 1
    @user51462: gcc has the same issue (not warning on some constraint violations without `-pedantic`) but at least the gcc help is a little more descriptive about what pedantic means: "Issue all the warnings demanded by strict ISO C". – sj95126 Dec 03 '22 at 05:16
  • 1
    More clearly, Clang and GCC do not conform to the C standard in their default modes (and technically not in any mode due to bugs and other issues but at least they try when asked), and people should not assume that “a C compiler” is “a standard C compiler.” – Eric Postpischil Dec 03 '22 at 11:09
  • @EricPostpischil, fair enough. I'm still a little shaken, though, as I like being able to predict what the code will do. As an aside, I still don't understand why clang's `-pedantic` worked in this case. – user51462 Dec 03 '22 at 11:45
  • @sj95126, yes, but it seems clang's definition is [different](https://stackoverflow.com/a/69946625/10841085) from gcc's. Or do they both mean the same thing, but just worded differently? – user51462 Dec 03 '22 at 12:40
  • 2
    @user51462: The exact conditions warned about using `-Wpedantic` are described in the [Diagnostic flag in clang](https://clang.llvm.org/docs/DiagnosticsReference.html#wpedantic) page. clang docs seemingly have no explanation about `-pedantic` vs `-Wpedantic` though clang often matches gcc behavior, and in gcc they're equivalent. – sj95126 Dec 03 '22 at 16:11
  • @user51462: Note that the initial releases of gcc predate the first ANSI C standard, and among the compiler's early features were a bunch of extensions to the C language (variable-length arrays, statement expressions, `typeof` and so forth). The ANSI C standard (aka C89) didn't include these extensions and required them to be errors (or rather, to "issue a diagnostic"). [...] – Nate Eldredge Dec 04 '22 at 18:43
  • Stallman (the original author of gcc) was apparently peeved about this. So when people wanted an ANSI conformant compiler, gcc added a conformant mode, but not as the default, and the option was given the rather petulant name of `-pedantic` as a bit of a jab at those stodgy jerks on the Standard committee. – Nate Eldredge Dec 04 '22 at 18:44
  • Thank you @NateEldredge, it seemed strange to me that neither gcc nor clang are ANSI conformant by default, but knowing the history helps. I wasn't aware of that when I posted my question, I just assumed I had misinterpreted the standard instead. – user51462 Dec 06 '22 at 22:17
  • @user51462 "I'm still a little shaken, though, as I like being able to predict what the code will do" If this little detail of clang's lack of conformance got you shaken, then how about the fact that clang can't even generate loops correctly? https://stackoverflow.com/q/59925618/584518 This was a massive bug rendering the compiler completely useless for a lot of purposes, particularly embedded systems programming. I'm still not sure if it's entirely fixed and I've dismissed clang as a toy compiler every since. – Lundin Dec 13 '22 at 12:46
2

First of all, please do not assume conforming behavior from the "gcc like" compilers including clang, unless you explicitly compile with -std=c17 -pedantic-errors. clang 14 does give a diagnostic if you use these options. That name "pedantic" was very poorly chosen by gcc back in the days. A better name would have been -conforming or something like that, because that's the behavior that this option actually unlocks.


  • So, why didn't clang issue a warning? Have I misinterpreted something?

    I believe you are reading the standard correctly. We can conclude that clang 14 is non-conforming without a -pedantic flag added.


  • However, when I compile it with clang 14, no diagnostic message is issued.

    There was apparently a known bug which has been corrected in clang 15. See Clang 15.0.0 release notes:

    The -Wimplicit-int warning diagnostic now defaults to an error in C99 and later. Prior to C2x, it may be downgraded to a warning with -Wno-error=implicit-int, or disabled entirely with -Wno-implicit-int. As of C2x, support for implicit int has been removed, and the warning options will have no effect. Specifying -Wimplicit-int in C89 mode will now issue warnings instead of being a noop.

    Therefore clang 15.0.0 (x86) with default options (with or without -pedantic-errors) gives:

    error: parameter 'a' was not declared, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int] void f(a)

    clang -Wno-implicit-int disables the error, as per the bug fix above.


  • Must a diagnostic be issued if a constraint violation can be "fixed" by the compiler applying some other provision in the Standard?

    Upon finding a constraint violation, a diagnostic must always be issued by a conforming implementation. This is normative behavior as per C17 5.1.1.3. See What must a C compiler do when it finds an error?


  • For example, the empty declaration list in the code above has always been a constraint violation (since C89)

    I think so too. The C90 6.7.1 constraints say

    If the declarator includes an identifier list, each declaration in the declaration list shall have at least one declarator, and those declarators shall declare only identifiers from the identifier list

    In your example a is an identifier.


  • So, would a pre-1999 ANSI-conformant compiler have still issued a diagnostic in this case?

    The difference between C90 and C99 is the syntax. C90 6.7.1 says declaration-specifiersopt and C99 6.9.1 says declaration-specifiers, no longer optional. Both standards has the declaration-listopt as optional, but as per the previously quoted constraints, there must be a declaration list in case a declaration with a named identifier is present.

    I guess some compilers may have read the optional part in the syntax like "in C90 you could omit both the declaration specifiers and the declaration list", which agrees with the syntax but not the constraints. It's a bit ambiguous, particularly since C90 6.7.1 also explicitly states:

    Any parameter that is not declared has type int.

    This part was removed in C99.

Lundin
  • 195,001
  • 40
  • 254
  • 396