Skip site navigation (1)Skip section navigation (2)
Date:      Mon,  4 Dec 2006 16:37:57 -0700 (MST)
From:      Timothy Smith <trangayesi@gmail.com>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/106355: macros in stdio.h non-portable (e.g., C++ ::feof() fails)
Message-ID:  <20061204233757.C92995C78@siva.hindu.god>
Resent-Message-ID: <200612042350.kB4No7Aq028007@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         106355
>Category:       kern
>Synopsis:       macros in stdio.h non-portable (e.g., C++ ::feof() fails)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Dec 04 23:50:06 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Timothy Smith
>Release:        FreeBSD 6.1-STABLE i386
>Organization:
>Environment:
System: FreeBSD siva.hindu.god 6.1-STABLE FreeBSD 6.1-STABLE #0: Sun Jun 18 13:23:52 MDT 2006 root@siva.hindu.god:/usr/obj/usr/src/sys/GENERIC i386


	
>Description:
FreeBSD's /usr/include/stdio.h defines a number of macros, such as
feof(), fileno(), etc.  These are not mentioned in manual pages, and I
can't find any reference in POSIX or C standards which allow it.

It causes code like the following C++ program to be non-portable.  It
compiles fine on Solaris, Linux, Windows, OS X.  It does fail on HPUX
as well, by the way, so FreeBSD isn't alone in using this technique.
Perhaps it is allowed by the standard, and the code is non-conformant.

<cstdio> does #undef most of these macros.  But checking c++ -E -dM
output after #include <cstdio> shows that at least fileno() is still
defined as a macro that won't allow ::fileno() to succeed:

#define fileno(p) (!__isthreaded ? __sfileno(p) : (fileno)(p))
>How-To-Repeat:
cat > fileno.cpp <<EOF
#include <stdio.h>
int main() { return ::feof(stdout); }
EOF
c++ -g -O -W -Wall fileno.cpp
c++ -E -dD fileno.cpp | tail
c++ -E -dM | grep -v '^#define _'

>Fix:
The workaround is obvious.  Just don't qualify functions from the
standard library as belonging to a namespace.  This doesn't work if a
class defines feof(), for example, and you need to call the global
feof() from inside it.  But arguably that's not a smart thing to do in
the first place.

The other workaround is also obvious:
#ifdef feof
#undef feof
#endif


It would be nice if standard library functions, included from
<stdio.h>, <stdlib.h>, etc., could be explicitly qualified with the
scope operator in C++ code.  A test for __cplusplus might do the
trick, perhaps something like:

#if __cplusplus
/* Hmmm, is this a problem for 6-character-unique symbol names? */
inline int __cpp_feof(FILE *p) {
	return !__isthreaded ? __sfeof(p) : (feof)(p);
}
#define feof(p) __cpp_feof(p)
#else
#define feof(p) (!__isthreaded ? __sfeof(p) : (feof)(p))
#endif /* __cplusplus */

Probably something similar could be done for other functions.


It might be a good idea to #undef fileno in cstdio as well.

>Release-Note:
>Audit-Trail:
>Unformatted:



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