ado@elsie.UUCP (Arthur David Olson) (05/05/89)
The GNU C Compiler, version 1.35, now generates a "conflicting types" message and refuses to compile when confronted with code such as. . . Script started on Thu May 4 22:03:53 1989 elsie$ cat try.c extern int whatever(); extern int whatever(char * format, ...); elsie$ /usr/local/bin/gcc -v try.c gcc version 1.35 /usr/local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -D__HAVE_68881__ -Dmc68020 try.c /tmp/cca15784.cpp GNU CPP version 1.35 /usr/local/lib/gcc-cc1 /tmp/cca15784.cpp -quiet -dumpbase try.c -version -o /tmp/cca15784.s GNU C version 1.35 (68k, MIT syntax) compiled by GNU C version 1.35. try.c:2: conflicting types for `whatever' try.c:2: A parameter list with an ellipsis can't match try.c:2: an empty parameter name list declaration. try.c:1: previous declaration of `whatever' elsie$ exit script done on Thu May 4 22:04:12 1989 If you can tell me wheter "try.c" above is [d[p]]ANS-compliant or not, I'd appreciate hearing from you by electronic mail. I'd also appreciate opinions on whether the code should be accepted even if it isn't compliant, so that newly written header files can contain prototypes without introducing the possibility of clashes with old-style header files. -- Space: Canada, 0 tries ever. Arthur David Olson ado@ncifcrf.gov ADO is a trademark of Ampex.
pardo@june.cs.washington.edu (David Keppel) (05/06/89)
An answer and a question: ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased) >gcc v. 1.35 generates a "conflicting types" message >and refuses to compile when confronted with code such as. . . > > extern int whatever(); > extern int whatever(char * format, ...); You can generate old and new-style functions declarations by doing something like #ifdef __STDC__ #define PROTO(x) x #else #define PROTO(x) () #endif extern int whatever PROTO((char *format, ...)); Now the question: I have asserted several times that you cannot (portably) call between prototyped and non-prototyped code. Thus, if a library is compiled without prototypes, you can call it where a prototyped declaration is in scope. Similarly, if the thing (library) was compiled with prototypes, it cannot be called from code that does not have prototypes in scope. Thus, the above macros (based on using __STDC__) are broke if you ever use them to call across compiler types. Yes? No? Maybe so? ;-D on ( Your local dime store philosipher ) Pardo -- pardo@cs.washington.edu {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo
rang@cpsin3.cps.msu.edu (Anton Rang) (05/06/89)
In article <8124@june.cs.washington.edu> pardo@june.cs.washington.edu (David Keppel) writes: >An answer and a question: >ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased) >>gcc v. 1.35 generates a "conflicting types" message >>and refuses to compile when confronted with code such as. . . >> >> extern int whatever(); >> extern int whatever(char * format, ...); >You can generate old and new-style functions declarations by doing >something like > #ifdef __STDC__ > #define PROTO(x) x > #else > #define PROTO(x) () > #endif > extern int whatever PROTO((char *format, ...)); This works fine when you are writing your own functions. I think the problem that Mr. Olson was referring to was when you are trying to add prototypes to standard libraries. At least, that's the problem I'm facing here--if you do "#include <stdio.h>" and then "#include <proto/stdio.h>", our system (Sun-3/280) will prototype the calls there. I haven't gotten 1.35 up yet, but if the above error message occurs in this situation, it means we have to either (1) give up support for the standard C compiler, or (2) duplicate all the include files, then edit them to use prototypes instead of externs. >Now the question: I have asserted several times that you cannot >(portably) call between prototyped and non-prototyped code. In which cases would this be true? The only time I can see it is if you have a prototype which overrides a default type conversion; i.e. if you have a function char *func(x) char x; then the obvious prototype "char *func(char x)" would be wrong. Doing the promotion gives you the prototype "char *func(int x)". Is there anything wrong with this that I'm missing? +---------------------------+------------------------+-------------------+ | Anton Rang (grad student) | "VMS Forever!" | VOTE on | | Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! | +---------------------------+------------------------+-------------------+ | Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu". | +---------------------------+------------------------+-------------------+
gwyn@smoke.BRL.MIL (Doug Gwyn) (05/08/89)
In article <8124@june.cs.washington.edu> pardo@uw-june.UUCP (David Keppel) writes: >Now the question: I have asserted several times that you cannot >(portably) call between prototyped and non-prototyped code. Wrong. <stdarg.h> does require a properly prototype for each variadic function, but otherwise if the argument types agree after default promotion rules are applied, a function can be declared either way.
ka@june.cs.washington.edu (Kenneth Almquist) (05/08/89)
>ado@elsie.UUCP (Arthur David Olson) writes: (paraphrased) >>gcc v. 1.35 generates a "conflicting types" message >>and refuses to compile when confronted with code such as. . . >> >> extern int whatever(); >> extern int whatever(char * format, ...); That's because these are incompatible. Bear with me for a few paragraphs of explanation. In traditional C, the number of arguments was not known at compile time. If a subroutine declared three arguments you could pass it four arguments. More usefully, you could pass the routine only two arguments if you knew that it was going to only reference its first two arguments on a particular call. This feature of C made some people unhappy because the "natural" calling sequence on some architectures requires a procedure to know how many arguments it was called with. An example is the 8086, where the "return from subroutine" instruction pops the arguments to the subroutine off the stack. C compilers for the 8086 and similar architectures have had to use a nonstandard calling sequences that do not require the callee to know the number of arguments. Two problems with using nonstandard calling sequences are: 1) It is likely to make function calls slower, and 2) It makes interfacing to code written in other languages more difficult. These problems (and possibly others) persuaded ANSI to require that the actual number of arguments be the same as the number of arguments declared, with the exception of functions which are explicitly declared to be varadic. (Apparently even thousands of PC users couldn't convince ANSI to eliminate printf. :-)) In other words, compilers are still required to support a form of subroutine call linkage which can handle a varying number of arguments, but they are only required to use this for procedures which are explicitly declared varadic. For other procedures, they are allowed to use calling conventions which require the called procedure to know the number of arguments at compile time. If a compiler takes advantage of this, then the compiler *must* know whether a function is varadic or not when it generates a call to that function. For example, consider following program: main() { printf("Hello, world\n"); exit(0); } This program is legal in traditional C, but in ANSI C all sorts of nasty things can happen. For example, on some machines it might make sense to have the callee *always* pop the arguments off the stack, and have the caller pass in the number of arguments when the function is varadic. In this case, the printf routine will treat the "hello, world\n" string as the number of arguments, and treat the next argument (which doesn't exist) as the format string. This will cause it to print out a bunch of garbage, pop some huge number of arguments off the stack (since the address of the "hello, world" string is likely to be a fairly large number), and return. When the program tries to call "exit" the stack pointer may very well be pointing at nonexistent memory, causing a core dump. I expect that an implementation which behaved like this would not sell very well, but it would conform to ANSI C. So to return to the original question, if you write >> extern int printf(); this tells the C compiler that printf is not a varadic function. The subsequent declaration >> extern int printf(char * format, ...); tells the C compiler that printf *is* a varadic function. Since the compiler may need to know whether or not printf is varadic in order to generate a call to it, giving the compiler conflicting information is rightly made illegal. Kenneth Almquist
ado@elsie.UUCP (Arthur David Olson) (05/12/89)
Thanks to everyone who replied to my question about gcc 1.35 flagging extern int whatever(); and extern int whatever(char * format, ...); as having conflicting types. The consensus is that while the presence of a "traditional" extern int whatever(); declaration tells a conforming compiler/interpreter nothing about the parameters of the function "whatever", it *does* represent a guarantee to the compiler/interpreter that "whatever" takes some fixed number of arguments. Folks interested in using gcc to compile X Window System applications may wish to make the attached change to their "fixincludes" script. -- Space: Canada, 0 tries ever. Arthur David Olson ado@ncifcrf.gov ADO is a trademark of Ampex. *** 1.5/fixincludes Thu May 11 17:02:28 1989 --- 1.6/fixincludes Thu May 11 17:02:28 1989 *************** *** 78,83 **** --- 78,106 ---- EOF fi + # Deal with yet another challenge, this in X11/Xmu.h + file=X11/Xmu.h + if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/X11 2>&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi + fi + + if [ -r ${LIB}/$file ]; then + echo Fixing $file sprintf declaration + ex ${LIB}/$file <<EOF + /^extern char \* sprintf();$/c + #ifndef __STDC__ + extern char * sprintf(); + #endif /* !defined __STDC__ */ + . + wq + EOF + fi + echo 'Removing unneeded directories:' cd $LIB files=`find . -type d -print | sort -r`