Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Feb 1999 02:01:55 +0000 (GMT)
From:      Terry Lambert <tlambert@primenet.com>
To:        Matthew.Alton@anheuser-busch.com (Alton, Matthew)
Cc:        Hackers@FreeBSD.ORG
Subject:   Re: C headers
Message-ID:  <199902060201.TAA25935@usr02.primenet.com>
In-Reply-To: <31B3F0BF1C40D11192A700805FD48BF90177670F@STLABCEXG011> from "Alton, Matthew" at Feb 5, 99 06:39:36 pm

next in thread | previous in thread | raw e-mail | index | archive | help
> Why does printf() non need #include <stdio.h> like the man page says?
> A student asked me why and I can't explain this inconsistency.

If you can explain symbol decoration in C++ objects, you can explain
why ANSI C requires prototypes in scope, not necessarily for compilation
and linking to succeed, but for proper function.



Header files are only needed if you require a prototype in scope to
deal with type promotion issues.

In general, the only C code that needs prototypes in scope is code
where the type promotion is not to type "int".

For most general purpose computer architectures (e.g., ones which
implement function arguments with promotion to int and passing on
the stack), this is not a problem.

For functions that accept/return types larger than "int" (i.e., where
"int" would represent a demotion in size), you will run into problems.
Such functions include any of the functions or system calls that take
an off_t argument (for example: lseek).

You will also run into problems with functions that take structure
pointers or return them (example: stat), since the structure will
not be defined without the header files.

You can see similar promotion related problems that ANSI failed to
address in the printf(3) function call.  Specifically, examine the
output of:

	#include <stdio.h>
	main()
	{
		long long	q_num = -3;
		long	l_num = -3;
		int	i_num = -3;
		short	s_num = -3;
		char	c_num = -3;

		printf( "a signed quad -3 is: %qx\n", q_num);
		printf( "a signed long -3 is: %lx\n", l_num);
		printf( "a signed int -3 is: %x\n", i_num);
		printf( "a signed short -3 is: %hx\n", s_num);
		printf( "a signed char -3 is: %x\n", c_num);
	}

The type promotion results in a sign extension error.  Probably the
proper connection would be to provide a "b" (for "byte") modifier
to the "x" and "X" types, e.g.:

		printf( "a signed char -3 is: %bx\n", num);



But using prototypes is actually a kludge around the fact that the
declaration and usage information is not stored in the symbol
definition for the function in the object file format, since if
it were, failure to abide by calling conventions could be caught
at link time, and would not have required complicating the language
(there are arguments that "C++ will replace C, so making the code
compilable with C++, which *demands* prototypes, is good"; people
who don't buy into C++ replacing C don't buy this argument).

Like "decorated" symbols in C++ works around the lack of class
attribution and overloading information in the object format, so
prototypes in scope in C files are meant to work around the lack
of argument and return type information for C functions.

So the fact that you will potentially get undetectable errors if
you compile without a prototype in scope can really be blamed on
lazy compiler writers who didn't want to update their linker
technology at the same time that they were adding assumptions to
their compiler.


Anyway, use the header files, and use the warning flags (they should
probably default "on", but I'll bet the compiler won't compile if you
do that 8-)).


					Terry Lambert
					terry@lambert.org
---
Any opinions in this posting are my own and not those of my present
or previous employers.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199902060201.TAA25935>