Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Abstract Syntax Tree for C programs Date: Tue, 04 Jun 2019 15:36:51 -0700 Organization: None to speak of Lines: 61 Message-ID: References: <475067fe-369c-4246-84a1-05b1a3a0c6be@googlegroups.com> <5dd4672f-a571-40bc-bb1a-c14f6c631eb7@googlegroups.com> <8d90e6a8-097d-4573-a88a-1f5f56dda26d@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="2e5690e26a3a02612d58fbc15f6a6031"; logging-data="13029"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX185tJ8gaeToEeZm2KYEyVfO" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:RtJ9XOPi3TuBPMlF1zy43CLG4d4= sha1:c/XifyBf/i6MSNSkI78kYyIdbeI= Xref: csiph.com comp.lang.c:144435 Keith Thompson writes: > guinness.tony@gmail.com writes: >> On Tuesday, 4 June 2019 11:24:44 UTC+1, Bart wrote: > [...] >>> How difficult can it be? For example: >>> >>> int main (void) { >>> fn(1,2,3,4); >>> fn("hello world"); >>> } >>> >>> There are no declarations of 'fn' visible; should this code pass or >>> fail? Apparently gcc passes this >> >> So it's a valid GnuC program. Irrelevant to a discussion in a C newsgroup. > > That depends on what you mean by "valid". > > In C90, the program has undefined behavior, because at most one > of the two calls passes correct arguments, but no diagnostic > is required. It violates a constraint in C99 and later. Recent > versions of gcc with default options will warn about an implicit > declaration of fn (but will not notice that the two calls are > inconsistent). > > This is why C has prototypes. Using them avoids this problem. > (I've seen arguments that non-prototype declarations can be useful > in some contexts, but this is not one of those contexts.) I was able to contrive a context in which the above code has defined behavior in C90 (but not in C99 or C11, where it's still a constraint violation): $ cat fn.c #include int fn(int a, int b, int c, int d) { exit(0); } $ cat c.c int main (void) { fn(1,2,3,4); fn("hello world"); } $ gcc -std=c90 -pedantic-errors fn.c c.c -o c $ ./c $ The only way to avoid undefined behavior is to prevent the second call from being evaluated. You could do the same thing in C99 or C11 by providing a visible non-prototype declaration for fn: int fn(); Of course the real solution is: Don't do that. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Will write code for food. void Void(void) { Void(); } /* The recursive call of the void */