On Thu, 11 Jul 2013, Tijl Coosemans wrote:
On 2013-07-11 06:21, Bruce Evans wrote:
On Wed, 10 Jul 2013, Garrett Wollman wrote:
<<On Wed, 10 Jul 2013 22:12:59 +0200, Tijl Coosemans <t...@freebsd.org> said:
I think isnan(double) and isinf(double) in math.h should only be
visible if (_BSD_VISIBLE || _XSI_VISIBLE) && __ISO_C_VISIBLE < 1999.
For C99 and higher there should only be the isnan/isinf macros.
I believe you are correct. POSIX.1-2008 (which is aligned with C99)
consistently calls isnan() a "macro", and gives a pseudo-prototype of
int isnan(real-floating x);
Almost any macro may be implemented as a function, if no conforming
program can tell the difference. It is impossible for technical reasons
to implement isnan() as a macro (except on weird implementations where
all real-floating types are physically the same). In the FreeBSD
implementation, isnan() is a macro, but it is also a function, and
the macro expands to the function in double precision:
% #define isnan(x) \
% ((sizeof (x) == sizeof (float)) ? __isnanf(x) \
% : (sizeof (x) == sizeof (double)) ? isnan(x) \
% : __isnanl(x))
The C99 standard says isnan is a macro. I would say that only means
defined(isnan) is true. Whether that macro then expands to function
calls or not is not important.
I think it means only that defined(isnan) is true. isnan() can still be
a function (declared or just in the compile-time namespace somewhere,
or in a library object). It is reserved in the compile-time namespace,
and the standard doesn't cover library objects, so conforming applications
can't reference either except via the isnan() macro (if that has its
strange historical implementation).
I don't see how any conforming program can access the isnan() function
directly. It is just as protected as __isnan() would be. (isnan)()
gives the function (the function prototype uses this), but conforming
programs can't do that since the function might not exist.
I don't think the standard allows a function to be declared with the same
name as a standard macro (it does allow the reverse: define a macro with
the same name as a standard function). I believe the following code is
C99 conforming but it currently does not compile with our math.h:
------
#include <math.h>
int (isnan)(int a, int b, int c) {
return (a + b + c);
}
------
I think isnan is just reserved, so you can't redefine it an any way. I
think the reverse is even less allowed. Almost any standard function may
be implemented as a macro, and then any macro definition of it would
conflict with the previous macro even more than with a previous prototype.
E.g.:
/* Header. */
void exit(int);
#define exit(x) __exit(x)
/* Application. */
#undef exit /* non-conforming */
#define exit(x) my_exit(x) /* conflicts without the #undef */
Now suppose the header doesn't define exit().
#define exit(x) my_exit(x)
This hides the protoype but doesn't automatically cause problems, especially
if exit() is not used after this point. But this is still non-conforming,
since exit() is reserved.
Here are some relevant parts of C99 (n869.txt):
%%%
-- Each identifier with file scope listed in any of the
following subclauses (including the future library
directions) is reserved for use as macro and as an
identifier with file scope in the same name space if
any of its associated headers is included.
[#2] No other identifiers are reserved. If the program
declares or defines an identifier in a context in which it
is reserved (other than as allowed by 7.1.4), or defines a
reserved identifier as a macro name, the behavior is
undefined.
[#3] If the program removes (with #undef) any macro
definition of an identifier in the first group listed above,
the behavior is undefined.
%%%
Without any include of a header that is specified to declare exit(),
file scope things are permitted for it, including defining it and
making it a static function, but not making it an extern function.
isnan is reserved for use as a macro and as an identifier with file
scope by the first clause above. Thus (isnan) cannot even be defined
as a static function. But (isnan) is not reserved in inner scopes.
I thought that declarations like "int (isnan);" are impossible since
they look like syntax errors, but this syntax seems to be allowed an
actually work with gcc-3.3.3 and TenDRA-5.0.0. So you can have
variables with silly names like (isnan) and (getchar) :-). However,
(NULL) for a variable name doesn't work, and (isnan) is a syntax error
for struct member names. The compilers may be correct in allowing
(isnan) but not (NULL) for variables. isnan happens to be function-like,
so the parentheses are special for (isnan), but the parentheses are not
special for (NULL). cpp confirms this -- NULL inside of parentheses
still gets expanded. The above quote of C99 can cover both since it
just says that isnan is reserved for use as a macro. In (isnan), the
parentheses prevent isnan being interpreted as a macro so the reservation
doesn't apply.
Bruce
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"