ANSI-C library functions can be generic intrinsic operators?

uunet!att!attunix!dfp uunet!att!attunix!dfp
Thu Apr 25 08:52:52 PDT 1991


Tom MacDonald answered some interesting David Hough questions on standard
C math library functions.  For the most part, I completely agree with
Tom's answers.  I naturally feel the need to add some thoughts as well.

>I believe it is entirely acceptable to diagnose the following:
>
>	main() { double x = sqrt(2); }
>
>because the <math.h> header is not included and by the rules of C an
>undeclared function is viewed as an external function that implicitly
>returns an `int'.  This conflicts with the standard because the external
>name `sqrt' is reserved as a function that returns a `double' and accepts
>one `double' argument.  As a reference, the Cray Standard C Compiler (version
>3.0) issues the following warning:
>
>  The call to "sqrt" does not match the standard math function prototype.

An implementation can issue as many warnings as it wants without affecting
its conformance.  Warnings are also very useful from the other side of
conformance: when it is hard to decide whether something really requires a
diagnostic, just issue a warning--you can't go wrong.

This is all a preamble to whether Cray's compiler could choose not to accept
the above program fragment.  If the implementation is only a "hosted", then
Tom is correct that the above code has undefined behavior and thus can be
rejected by the compiler.  On the other hand, if the implementation is
intended to be "freestanding" as well (like most C compilers; otherwise you
couldn't use it to build your OS), then sqrt is not a reserved external
linkage identifier.

>First - let me short circuit any comments about the recently exposed hole
>in the C standard about function call operators not defining the result type
>of the operator.  Let's assume the standard states the result type of a
>function call operator with the first operand having type: "pointer to function
>returning type" is "type".  Without some information like this all function
>calls are unspecified behavior and that makes any discussion on this subject
>worthless.

This is an interesting item, as yet to be answered by the interpretations
body.  I agree with Tom's suggestion that the type of an expression that
is a call to a function that returns T should be T.  This, however, does not
require that certain promotions have not occurred in the underlying return
code.  Moreover, since there is now agreement that the value returned by a
function is not an object, the integral promotions should be applied:

	char f(void); int s = sizeof(int) - sizeof f();

should initialize s with 0.  More on this below.

>Second - I do not believe that this is a conforming implementation because
>the macro __generic_intrinsic_sqrt, as defined, would conflict with structure
>member names, label names, local automatic names, etc.  Including the <math.h>
>header does not grant license to distort all names that have the same
>spelling as the library functions.  However, the following is perfectly
>acceptable:
>
>		extern double sqrt(double);
>		#define sqrt(X) __generic_intrinsic_sqrt(X)
>
>because it limits itself to function call like expressions.

I disagree.  There is nothing that prevents a definition such as

	#define sqrt __generic_intrinsic_sqrt

in an implementation's <math.h>.  Certainly Tom is correct that this form of
macro definition cannot have a replacement turned off by surrounding it with
parentheses, but that doesn't matter.  It also doesn't matter that it would
cause all nonfunction uses of the name sqrt to be replaced as well.  An
implementation can tell the difference between a function call and other uses
and can adjust itself as it chooses.

>> Can sqrt(float) return a float?
>> Can sqrt(long double) return a long double?

Tom says "yes" to the first and "no" to the second.  I say that they are
both "yes".  Assuming that we agree that the type of a call to sqrt is
double, the issue is whether more or less precision is permitted.  We agree
that an implementation can determine that in the first case no more precision
than float is necessary.  Because the magnitude of the result of sqrt is not
greater than its incoming argument, the only behavior that can be tested
against is situations in which precision would be lost if the values were
narrowed to double.  As the library functions are special once its header is
included, there is no rule that I can find that requires narrowing any more
than narrowing is required in a floating expression.

For math functions for which the returned value can trigger ERANGE, a strictly
conforming program can depend on errno being set.  However, if a program uses
virtually any of the NCEG numeric subgroup extensions the errno-setting
requirement can probably be by-passed.

Dave



More information about the Numeric-interest mailing list