About 7.1.4 Use of library functions

21 views
Skip to first unread message

Vincent Lefevre

unread,
Oct 20, 2010, 11:51:02 AM10/20/10
to
In N1256 (ISO/IEC 9899:TC3):

7.1.4 Use of library functions

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as a value outside the
domain of the function, or a pointer outside the address space of
the program, or a null pointer, or a pointer to non-modifiable
^^^^^^^^^^^^^^
storage when the corresponding parameter is not const-qualified) or
a type (after promotion) not expected by a function with variable
^^^^^^^^^^^^^^^
number of arguments, the behavior is undefined. [...]

First, concerning the null pointer, is it really an invalid value?
This would mean that one cannot output a null pointer with printf
and %p (the detailed description doesn't say that it is allowed,
so that the default statement of 7.1.4 applies).

Second, what about "after promotion"? printf-like functions don't
do promotions. I suppose that they are not concerned. But what
about the other functions? Is promotion guaranteed to occur when
the function is implemented by a macro? The standard seems to be
silent on this point.

--
Vincent Lef�vre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Ar�naire project (LIP, ENS-Lyon)

Keith Thompson

unread,
Oct 20, 2010, 1:19:25 PM10/20/10
to
Vincent Lefevre <vincen...@vinc17.net> writes:
> In N1256 (ISO/IEC 9899:TC3):
>
> 7.1.4 Use of library functions
>
> Each of the following statements applies unless explicitly stated
> otherwise in the detailed descriptions that follow: If an argument
> to a function has an invalid value (such as a value outside the
> domain of the function, or a pointer outside the address space of
> the program, or a null pointer, or a pointer to non-modifiable
> ^^^^^^^^^^^^^^
> storage when the corresponding parameter is not const-qualified) or
> a type (after promotion) not expected by a function with variable
> ^^^^^^^^^^^^^^^
> number of arguments, the behavior is undefined. [...]
>
> First, concerning the null pointer, is it really an invalid value?
> This would mean that one cannot output a null pointer with printf
> and %p (the detailed description doesn't say that it is allowed,
> so that the default statement of 7.1.4 applies).

Interesting. I'm not sure the phrase "such as" really means that all
the mentioned cases are invalid. The description of time() says (or
very strongly implies) that a null pointer is a valid argument.

I suppose the failure to mention null pointers in the description of the
"%p" option is an oversight. Resorting to common sense, I'm sure the
intent is that printf("%p\n", (void*)NULL) is valid (and produces some
implementation-defined output).

> Second, what about "after promotion"? printf-like functions don't
> do promotions. I suppose that they are not concerned. But what
> about the other functions? Is promotion guaranteed to occur when
> the function is implemented by a macro? The standard seems to be
> silent on this point.

Yes, printf-like functions do promotions. Specifically, the "default
argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
the format string. For example, short is promoted to int, and float to
double.

As for functions implemented by macros, I'm sure the intent is that
at least correct calls work the same way as actual function calls.
(I suppose some incorrect calls might not be diagnosed.) Promotion
could be simulated by having the macro definition cast its argument
to the expected type.

Aside from promotion issues, it's not clear that this:

sin(x) + cos(x)

necessarily works as expected. sin() and cos() potentially modify
errno; if they're implemented as macros, the two modifications
might not be separated by a sequence point. Sane implementations
will avoid this, but insane (or sloppy) conforming implementations
might not.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Vincent Lefevre

unread,
Oct 20, 2010, 8:17:19 PM10/20/10
to
In article <lnd3r4y...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

> Yes, printf-like functions do promotions. Specifically, the "default
> argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
> the format string. For example, short is promoted to int, and float to
> double.

Actually I meant implicit conversions, for which nothing is said.
For instance, can log1p have an implementation by the following?

#define log1p(x) log(1+(x))

(Exactly like this, it is bad for the accuracy, but this is just a
simple example.)

If the user is expected to provide a double argument, this is OK.
Or does the implementation need to perform the conversion like

#define log1p(x) log(1+(double)(x))

in order to allower the user to provide an argument in another type
(such as int, in which case the call would fail for INT_MAX)?

> As for functions implemented by macros, I'm sure the intent is that
> at least correct calls work the same way as actual function calls.
> (I suppose some incorrect calls might not be diagnosed.) Promotion
> could be simulated by having the macro definition cast its argument
> to the expected type.

So, you would say that one should have something like

#define log1p(x) log(1+(double)(x))

Eric Sosman

unread,
Oct 20, 2010, 9:23:26 PM10/20/10
to
On 10/20/2010 11:51 AM, Vincent Lefevre wrote:
> In N1256 (ISO/IEC 9899:TC3):
>
> 7.1.4 Use of library functions
>
> Each of the following statements applies unless explicitly stated
> otherwise in the detailed descriptions that follow: If an argument
> to a function has an invalid value (such as a value outside the
> domain of the function, or a pointer outside the address space of
> the program, or a null pointer, or a pointer to non-modifiable
> ^^^^^^^^^^^^^^
> storage when the corresponding parameter is not const-qualified) or
> a type (after promotion) not expected by a function with variable
> ^^^^^^^^^^^^^^^
> number of arguments, the behavior is undefined. [...]
>
> First, concerning the null pointer, is it really an invalid value?
> This would mean that one cannot output a null pointer with printf
> and %p (the detailed description doesn't say that it is allowed,
> so that the default statement of 7.1.4 applies).

I think the list is intended to be exemplary, not prescriptive.
For example, free(NULL) is perfectly well-defined.

> Second, what about "after promotion"? printf-like functions don't
> do promotions.

What do you mean here? For all variable-argument functions,
including printf() and its brethren, the caller performs the "default
argument promotions" described in 6.5.2.2p6.

> I suppose that they are not concerned. But what
> about the other functions? Is promotion guaranteed to occur when
> the function is implemented by a macro? The standard seems to be
> silent on this point.

It is possible, I guess, that the arguments to a macro-ized
version of a function might be subject to different promotions than
if the actual function were called. For example, a `sqrt(x)' macro
might behave differently with a `float' argument than would the
sqrt() function itself (let's just ignore <tgmath.h>, shall we?).
But aside from issues of floating-point precision I cannot think,
off-hand, of a Standard library function for which this would make
a difference. (I emphasize "off-hand," meaning that I haven't
given the matter a lot of thought and may well be wrong.)

--
Eric Sosman
eso...@ieee-dot-org.invalid

Keith Thompson

unread,
Oct 21, 2010, 12:14:47 AM10/21/10
to
Vincent Lefevre <vincen...@vinc17.net> writes:
> In article <lnd3r4y...@nuthaus.mib.org>,
> Keith Thompson <ks...@mib.org> wrote:
>
>> Yes, printf-like functions do promotions. Specifically, the "default
>> argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
>> the format string. For example, short is promoted to int, and float to
>> double.
>
> Actually I meant implicit conversions, for which nothing is said.
> For instance, can log1p have an implementation by the following?
>
> #define log1p(x) log(1+(x))
>
> (Exactly like this, it is bad for the accuracy, but this is just a
> simple example.)
>
> If the user is expected to provide a double argument, this is OK.
> Or does the implementation need to perform the conversion like
>
> #define log1p(x) log(1+(double)(x))
>
> in order to allower the user to provide an argument in another type
> (such as int, in which case the call would fail for INT_MAX)?
>
>> As for functions implemented by macros, I'm sure the intent is that
>> at least correct calls work the same way as actual function calls.
>> (I suppose some incorrect calls might not be diagnosed.) Promotion
>> could be simulated by having the macro definition cast its argument
>> to the expected type.
>
> So, you would say that one should have something like
>
> #define log1p(x) log(1+(double)(x))

Yes, I'd say that a macro implementation has to convertits argument. My
basis for this is more just common sense (the macro should work the same
way as the function) than anything actually stated in the Standard.

Or this would probably also work, with the "usual arithmetic
conversions" performed by "+" doing the same job.

#define log1p(x) (log(1.0+(x)))

There might be some odd corner cases. Since I'm not an implementer,
I'm not obligated to think about them. 8-)}

Note that I've also added parentheses around the entire definition.
I can't think of a case off the top of my head where this matters,
but better safe than sorry.

Jun Woong

unread,
Oct 21, 2010, 3:08:29 AM10/21/10
to
Vincent Lefevre <vincent-n...@vinc17.net> wrote:
> In article <lnd3r4ye76....@nuthaus.mib.org>,

>   Keith Thompson <ks...@mib.org> wrote:
>
> > Yes, printf-like functions do promotions.  Specifically, the "default
> > argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
> > the format string.  For example, short is promoted to int, and float to
> > double.
>
> Actually I meant implicit conversions, for which nothing is said.
> For instance, can log1p have an implementation by the following?
>
> #define log1p(x) log(1+(x))
>
> (Exactly like this, it is bad for the accuracy, but this is just a
> simple example.)
>
> If the user is expected to provide a double argument, this is OK.
> Or does the implementation need to perform the conversion like
>
> #define log1p(x) log(1+(double)(x))
>
> in order to allower the user to provide an argument in another type
> (such as int, in which case the call would fail for INT_MAX)?

Basically, yes, except that an implementation is not allowed to use
that keyword directly in macros. For example, a strictly conforming
program can do this:

#include <limits.h>
#include <math.h>

int main(void)
{
int x = INT_MAX;
#define double int
log1p(x);
#undef double
}

>
> > As for functions implemented by macros, I'm sure the intent is that
> > at least correct calls work the same way as actual function calls.
> > (I suppose some incorrect calls might not be diagnosed.)  Promotion
> > could be simulated by having the macro definition cast its argument
> > to the expected type.
>
> So, you would say that one should have something like
>
> #define log1p(x) log(1+(double)(x))

Precisely,

typedef double __double;
#define log1p(x) (log(1+(__double)(x)))

However, there is still a problem. Suppose a macro version of a
function
that takes an integer argument:

typedef int __int;
#define func(x) (real_func((__int)(x)))

This implementation is silent on this:

int *p;
func(p);

while not on this:

int *p;
(func)(p);


--
Jun, Woong (woong.jun at gmail.com)

Message has been deleted

Vincent Lefevre

unread,
Oct 21, 2010, 4:00:05 AM10/21/10
to
In article <i9o4oa$98h$1...@news.eternal-september.org>,
Eric Sosman <eso...@ieee-dot-org.invalid> wrote:

> On 10/20/2010 11:51 AM, Vincent Lefevre wrote:
> > In N1256 (ISO/IEC 9899:TC3):
> >
> > 7.1.4 Use of library functions
> >
> > Each of the following statements applies unless explicitly stated
> > otherwise in the detailed descriptions that follow: If an argument
> > to a function has an invalid value (such as a value outside the
> > domain of the function, or a pointer outside the address space of
> > the program, or a null pointer, or a pointer to non-modifiable
> > ^^^^^^^^^^^^^^
> > storage when the corresponding parameter is not const-qualified) or
> > a type (after promotion) not expected by a function with variable
> > ^^^^^^^^^^^^^^^
> > number of arguments, the behavior is undefined. [...]
> >
> > First, concerning the null pointer, is it really an invalid value?
> > This would mean that one cannot output a null pointer with printf
> > and %p (the detailed description doesn't say that it is allowed,
> > so that the default statement of 7.1.4 applies).

> I think the list is intended to be exemplary, not prescriptive.
> For example, free(NULL) is perfectly well-defined.

Yes, but this case is explicitly defined in the specification of
free(), thus falls under "unless explicitly stated" in the first
line of 7.1.4.

> > Second, what about "after promotion"? printf-like functions don't
> > do promotions.

> What do you mean here? For all variable-argument functions,
> including printf() and its brethren, the caller performs the "default
> argument promotions" described in 6.5.2.2p6.

Sorry, I was thinking in fact of implicit conversions. So, giving
the integer 1 for %g is incorrect because only default argument
promotion is done in printf, but for other functions like sin(1),
there's no problem for an implementation as a function. But what
worries me is that the standard says nothing explicit if sin() is
implemented as a macro.

--
Vincent Lefèvre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>


100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>

Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)

Vincent Lefevre

unread,
Oct 21, 2010, 4:20:02 AM10/21/10
to
In article <lneibk2...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:

> Yes, I'd say that a macro implementation has to convertits argument. My
> basis for this is more just common sense (the macro should work the same
> way as the function) than anything actually stated in the Standard.

Yes. But on this subject, the standard says "Any invocation of a
library function that is implemented as a macro shall expand to
code that evaluates each of its arguments exactly once, fully
protected by parentheses where necessary, so it is generally safe
to use arbitrary expressions as arguments.", but nothing about
the type of the arguments.

> Or this would probably also work, with the "usual arithmetic
> conversions" performed by "+" doing the same job.

> #define log1p(x) (log(1.0+(x)))

There can a small difference if the type of x is long double. I mean
that if the function definition uses the same formula as the macro,
the function and the macro can return different results due to the
double rounding in the macro on a "long double" argument (my point
here is the consistency, not the accuracy).

> There might be some odd corner cases. Since I'm not an implementer,
> I'm not obligated to think about them. 8-)}

> Note that I've also added parentheses around the entire definition.
> I can't think of a case off the top of my head where this matters,
> but better safe than sorry.

I'd be interested to know if they are important. Several libraries
do not always use parentheses in such cases, e.g. the glibc
/usr/include/stdio.h has:

#define getc(_fp) _IO_getc (_fp)
#define putc(_ch, _fp) _IO_putc (_ch, _fp)

--
Vincent Lefèvre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>


100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>

Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)

James Kuyper

unread,
Oct 21, 2010, 7:25:11 AM10/21/10
to
On 10/20/2010 08:17 PM, Vincent Lefevre wrote:
> In article<lnd3r4y...@nuthaus.mib.org>,
> Keith Thompson<ks...@mib.org> wrote:
>
>> Yes, printf-like functions do promotions. Specifically, the "default
>> argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
>> the format string. For example, short is promoted to int, and float to
>> double.
>
> Actually I meant implicit conversions, for which nothing is said.
> For instance, can log1p have an implementation by the following?
>
> #define log1p(x) log(1+(x))
>
> (Exactly like this, it is bad for the accuracy, but this is just a
> simple example.)
> If the user is expected to provide a double argument, this is OK.
> Or does the implementation need to perform the conversion like
>
> #define log1p(x) log(1+(double)(x))
>
> in order to allower the user to provide an argument in another type
> (such as int, in which case the call would fail for INT_MAX)?

log1p() is supposed to meet all of the requirements specified by the
standard for that function, including those requirements which are
implicit in the declaration given by the standard for that function,
regardless of whether it's implemented as an actual function or as a
function-like macro. The only exception is that, if implemented as a
function-like macro, the macro invocation might expand to code which
does not have the same sequence points as the function call. The fact
that log(1+(x)) doesn't meet some of those requirements renders it a
non-conforming implementation.

Implementation as a macro allows different behavior with respect to
#ifdef, #ifndef, #if defined(), and the stringizing operator #; but not
in any other regard.

Wojtek Lerch

unread,
Oct 21, 2010, 8:47:09 AM10/21/10
to
On 21/10/2010 7:25 AM, James Kuyper wrote:
> On 10/20/2010 08:17 PM, Vincent Lefevre wrote:
>> #define log1p(x) log(1+(double)(x))
...

> Implementation as a macro allows different behavior with respect to
> #ifdef, #ifndef, #if defined(), and the stringizing operator #; but not
> in any other regard.

One other difference is that some incorrect calls that would normally
violate a constraint do not require a diagnostic when the implementation
is a macro with an explicit cast like the above:

log1p( "Hello" );

Keith Thompson

unread,
Oct 21, 2010, 11:11:47 AM10/21/10
to

That's a consequence, perhaps an unavoidable one, of some macro
implementations of library functions, but I don't see such permission
stated in the standard.

Vincent Lefevre

unread,
Oct 21, 2010, 11:50:51 AM10/21/10
to
In article <6e4b7eff-e396-4d4f...@35g2000prt.googlegroups.com>,
Jun Woong <wo...@icu.ac.kr> wrote:

> Basically, yes, except that an implementation is not allowed to use
> that keyword directly in macros. For example, a strictly conforming
> program can do this:

> #include <limits.h>
> #include <math.h>

> int main(void)
> {
> int x = INT_MAX;
> #define double int
> log1p(x);
> #undef double
> }

[...]

> Precisely,

> typedef double __double;
> #define log1p(x) log(1+(__double)(x))

But if the user is allowed to #define a keyword like "double", is
this also the case for "log"? For instance, is the following program
strictly conforming?

#include <math.h>
int main(void)
{
int x = 32767;
#define double int
#undef log
#define log foo
log1p(x);
#undef double
#undef log
return 0;
}

If it is, then even

typedef double __double;
#define log1p(x) log(1+(__double)(x))

is incorrect, and I don't see how a macro could be defined if the
implementation doesn't provide some __log function.

--
Vincent Lefèvre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>


100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>

Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)

Vincent Lefevre

unread,
Oct 21, 2010, 11:58:32 AM10/21/10
to

> Basically, yes, except that an implementation is not allowed to use
> that keyword directly in macros. For example, a strictly conforming
> program can do this:

> #include <limits.h>
> #include <math.h>

> int main(void)
> {
> int x = INT_MAX;
> #define double int
> log1p(x);
> #undef double
> }

Hmm... after thinking a bit more about it, are you sure that this
is a strictly conforming program?

What about the following, then?

#include <assert.h>

int main(void)
{
#define void error
assert(1);
#undef void
return 0;
}

This is very similar, but doesn't work with the glibc.

--
Vincent Lefèvre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>


100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>

Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)

Vincent Lefevre

unread,
Oct 21, 2010, 12:08:52 PM10/21/10
to
In article <20101021155533$76...@prunille.vinc17.org>,
Vincent Lefevre <vincen...@vinc17.net> wrote:

> What about the following, then?

> #include <assert.h>

> int main(void)
> {
> #define void error
> assert(1);
> #undef void
> return 0;
> }

N1256 says in 7.1.2#4 (Standard headers): "The program shall not
have any macros with names lexically identical to keywords currently
defined prior to the inclusion." but in my program, the macro is
defined after the header inclusion, so that I think that's a bug
in the glibc.

Eric Sosman

unread,
Oct 21, 2010, 9:36:18 PM10/21/10
to
On 10/20/2010 8:17 PM, Vincent Lefevre wrote:
> In article<lnd3r4y...@nuthaus.mib.org>,
> Keith Thompson<ks...@mib.org> wrote:
>
>> Yes, printf-like functions do promotions. Specifically, the "default
>> argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
>> the format string. For example, short is promoted to int, and float to
>> double.
>
> Actually I meant implicit conversions, for which nothing is said.

What do you mean by "nothing is said?" The Standard gives a
detailed description of the conversions that occur for argument
expressions passed to "..." parameters (or to functions lacking
prototypes). In what conceivable sense is that "nothing?"

> For instance, can log1p have an implementation by the following?
>
> #define log1p(x) log(1+(x))
>
> (Exactly like this, it is bad for the accuracy, but this is just a
> simple example.)

I don't think this would be valid, for the reasons you point out.
A "masking macro" for a library function must mimic the actual function
(which must also exist as a function), and this macro would be a poor
mimic.

On the other hand, the mimicry is not required to be 100% perfect.
The Standard requires that the macro evaluate each argument exactly
once (with a couple special-dispensation exceptions), but need not
produce the same sequence points. And the guarantees on FP accuracy
are weak enough that I don't think the function and macro can be held
to a bit-for-bit agreement in results. It is possible that the macro
you show would be considered "valid, but of poor quality" rather than
"wrong, r-o-n-g, wrong." We'll leave that one to the language lawyers.

> If the user is expected to provide a double argument, this is OK.
> Or does the implementation need to perform the conversion like
>
> #define log1p(x) log(1+(double)(x))

My preference would be for `log(1.0+(x))', but since the macro
is already a poor replacement for the function it scarcely matters.

> in order to allower the user to provide an argument in another type
> (such as int, in which case the call would fail for INT_MAX)?
>
>> As for functions implemented by macros, I'm sure the intent is that
>> at least correct calls work the same way as actual function calls.

For suitable and hand-waving values of "the same way," yes.

>> (I suppose some incorrect calls might not be diagnosed.) Promotion
>> could be simulated by having the macro definition cast its argument
>> to the expected type.
>
> So, you would say that one should have something like
>
> #define log1p(x) log(1+(double)(x))

I'm afraid I don't understand the intent of this question.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Jun Woong

unread,
Oct 21, 2010, 9:56:44 PM10/21/10
to
Keith Thompson <ks...@mib.org> wrote:

> Wojtek Lerch <wojte...@yahoo.ca> writes:
> > On 21/10/2010 7:25 AM, James Kuyper wrote:
> >> On 10/20/2010 08:17 PM, Vincent Lefevre wrote:
> >>> #define log1p(x) log(1+(double)(x))
> > ...
> >> Implementation as a macro allows different behavior with respect to
> >> #ifdef, #ifndef, #if defined(), and the stringizing operator #; but not
> >> in any other regard.
>
> > One other difference is that some incorrect calls that would normally
> > violate a constraint do not require a diagnostic when the implementation
> > is a macro with an explicit cast like the above:
>
> >    log1p( "Hello" );
>
> That's a consequence, perhaps an unavoidable one, of some macro
> implementations of library functions, but I don't see such permission
> stated in the standard.

As I recall, Larry Jones has suggested a way to get around that
problem by using sizeof, for example:

typedef double __double;
#define log1p(x) (sizeof((log1p)(x)), log(1+(__double)(x)))

The problem here is, however, that the standard still allows the
keyword sizeof to be masked by a user-defined macro and there is
nothing such as typedef for sizeof, which is why my implementation
provides _Sizeof as a synonym of sizeof.

Jun Woong

unread,
Oct 21, 2010, 10:01:30 PM10/21/10
to
Vincent Lefevre <vincent-n...@vinc17.net> wrote:
> In article <6e4b7eff-e396-4d4f-83b2-6df1a12f7...@35g2000prt.googlegroups.com>,

No. Differently from keywords that can be masked by macros after
#including standard headers, most identifiers for the standard
library functions are reserved by the standard. (I'm not with my copy
of the standard now, sorry for not pointing out the section number.)

Vincent Lefevre

unread,
Oct 22, 2010, 8:05:42 AM10/22/10
to
In article <i9qpt6$815$1...@news.eternal-september.org>,
Eric Sosman <eso...@ieee-dot-org.invalid> wrote:

> On 10/20/2010 8:17 PM, Vincent Lefevre wrote:
> > In article<lnd3r4y...@nuthaus.mib.org>,
> > Keith Thompson<ks...@mib.org> wrote:
> >
> >> Yes, printf-like functions do promotions. Specifically, the "default
> >> argument promotions" (C99 6.5.2.2p6-7) are performed on arguments after
> >> the format string. For example, short is promoted to int, and float to
> >> double.
> >
> > Actually I meant implicit conversions, for which nothing is said.

> What do you mean by "nothing is said?" The Standard gives a
> detailed description of the conversions that occur for argument
> expressions passed to "..." parameters (or to functions lacking
> prototypes). In what conceivable sense is that "nothing?"

I mean when a function is also implemented by a macro. Can the user
still rely on the implicit conversion?

> > For instance, can log1p have an implementation by the following?
> >
> > #define log1p(x) log(1+(x))
> >
> > (Exactly like this, it is bad for the accuracy, but this is just a
> > simple example.)

> I don't think this would be valid, for the reasons you point out.
> A "masking macro" for a library function must mimic the actual function
> (which must also exist as a function), and this macro would be a poor
> mimic.

In what sense?

Vincent Lefevre

unread,
Oct 22, 2010, 8:17:58 AM10/22/10
to
In article <930ae025-c00d-47dd...@37g2000prx.googlegroups.com>,
Jun Woong <wo...@icu.ac.kr> wrote:

> Vincent Lefevre <vincent-n...@vinc17.net> wrote:
> > But if the user is allowed to #define a keyword like "double", is
> > this also the case for "log"? For instance, is the following program
> > strictly conforming?
> >
> > #include <math.h>
> > int main(void)
> > {
> > � int x = 32767;
> > #define double int
> > #undef log
> > #define log foo
> > � log1p(x);
> > #undef double
> > #undef log
> > � return 0;
> >
> > }

> No. Differently from keywords that can be masked by macros after
> #including standard headers, most identifiers for the standard
> library functions are reserved by the standard. (I'm not with my copy
> of the standard now, sorry for not pointing out the section number.)

OK, this is forbidden by "7.1.3 Reserved identifiers" #1

Each identifier with file scope listed in any of the following
subclauses (including the future library directions) is reserved
for use as a macro name and as an identifier with file scope in
the same name space if any of its associated headers is included.

and #2 (and though 7.1.4 allows to #undef such a macro, its name is
still reserved, so that a #define to redefine it is incorrect).

--
Vincent Lef�vre <vin...@vinc17.net> - Web: <http://www.vinc17.net/>


100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>

Tim Rentsch

unread,
Oct 22, 2010, 12:19:46 PM10/22/10
to
Jun Woong <wo...@icu.ac.kr> writes:

> Keith Thompson <ks...@mib.org> wrote:
>> Wojtek Lerch <wojte...@yahoo.ca> writes:
>> > On 21/10/2010 7:25 AM, James Kuyper wrote:
>> >> On 10/20/2010 08:17 PM, Vincent Lefevre wrote:
>> >>> #define log1p(x) log(1+(double)(x))
>> > ...
>> >> Implementation as a macro allows different behavior with respect to
>> >> #ifdef, #ifndef, #if defined(), and the stringizing operator #; but not
>> >> in any other regard.
>>
>> > One other difference is that some incorrect calls that would normally
>> > violate a constraint do not require a diagnostic when the implementation
>> > is a macro with an explicit cast like the above:
>>
>> > log1p( "Hello" );
>>
>> That's a consequence, perhaps an unavoidable one, of some macro
>> implementations of library functions, but I don't see such permission
>> stated in the standard.
>
> As I recall, Larry Jones has suggested a way to get around that
> problem by using sizeof, for example:
>
> typedef double __double;
> #define log1p(x) (sizeof((log1p)(x)), log(1+(__double)(x)))
>
> The problem here is, however, that the standard still allows the

> keyword sizeof to be masked by a user-defined macro [snip]

Can be done without using sizeof, e.g.,

#define log1p(x) ( 1 ? log(1+(__double)(x)) : log1p((x)) )

which also has the advantage that it applies to functions
whose return type is (void).

Eric Sosman

unread,
Oct 22, 2010, 9:34:00 PM10/22/10
to
On 10/22/2010 8:05 AM, Vincent Lefevre wrote:
> In article<i9qpt6$815$1...@news.eternal-september.org>,

> Eric Sosman<eso...@ieee-dot-org.invalid> wrote:
>
>> On 10/20/2010 8:17 PM, Vincent Lefevre wrote:
>>> [...]

>>> For instance, can log1p have an implementation by the following?
>>>
>>> #define log1p(x) log(1+(x))
>>>
>>> (Exactly like this, it is bad for the accuracy, but this is just a
>>> simple example.)
>
>> I don't think this would be valid, for the reasons you point out.
>> A "masking macro" for a library function must mimic the actual function
>> (which must also exist as a function), and this macro would be a poor
>> mimic.
>
> In what sense?

"For the reasons you point out:" If `x' is an int with the
value INT_MAX (or unsigned int with value UINT_MAX, or long with ...),
adding an unadorned `1' produces a surprising value (or something
even stranger). In any event, the outcome is quite different from
that the actual function would give: log(1+(UINT_MAX)) = -Inf, maybe,
but log1p(UINT_MAX) = ~11 or ~22 or ~44 or something like that.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Jun Woong

unread,
Oct 27, 2010, 11:09:00 PM10/27/10
to
Tim Rentsch <t...@alumni.caltech.edu> wrote:
> Jun Woong <wo...@icu.ac.kr> writes:
[...]

>
> > As I recall, Larry Jones has suggested a way to get around that
> > problem by using sizeof, for example:
>
> >     typedef double __double;
> >     #define log1p(x) (sizeof((log1p)(x)), log(1+(__double)(x)))
>
> > The problem here is, however, that the standard still allows the
> > keyword sizeof to be masked by a user-defined macro [snip]
>
> Can be done without using sizeof, e.g.,
>
>   #define log1p(x) (  1 ? log(1+(__double)(x)) : log1p((x))  )

This also looks good. All compilers would have no difficulty in
optimizing the conditional expression out; even academic ones do
that.

> which also has the advantage that it applies to functions
> whose return type is (void).

The sizeof version can also be used for void functions by
introducing a comma operator in it.

There are other problems that can be solved by using the sizeof
operator in macro definitions, which may look very tricky but works
well in practice. Implementing <tgmath.h> on an implementation with
no support for function overloading is an example. I think preventing
a s.c. program from #defining sizeof helps to write a portable
library.

Tim Rentsch

unread,
Nov 13, 2010, 12:09:01 PM11/13/10
to
Jun Woong <wo...@icu.ac.kr> writes:

> Tim Rentsch <t...@alumni.caltech.edu> wrote:
>> Jun Woong <wo...@icu.ac.kr> writes:
> [...]
>>
>> > As I recall, Larry Jones has suggested a way to get around that
>> > problem by using sizeof, for example:
>>
>> > typedef double __double;
>> > #define log1p(x) (sizeof((log1p)(x)), log(1+(__double)(x)))
>>
>> > The problem here is, however, that the standard still allows the
>> > keyword sizeof to be masked by a user-defined macro [snip]
>>
>> Can be done without using sizeof, e.g.,
>>
>> #define log1p(x) ( 1 ? log(1+(__double)(x)) : log1p((x)) )
>
> This also looks good. All compilers would have no difficulty in
> optimizing the conditional expression out; even academic ones do
> that.
>
>> which also has the advantage that it applies to functions
>> whose return type is (void).
>
> The sizeof version can also be used for void functions by
> introducing a comma operator in it.

Quite right. In some situations that might be preferable.

Reply all
Reply to author
Forward
0 new messages