Is this #define legal?

S

Sensei

Hi! I'm concerned about the legality of such a definition:

#define funcX funcY

where funcX belongs to the *standard* C functions. Is it legal to do
this? The standard says "any function declared in a header may be
additionally implemented as a macro defined in the header, so a library
function should not be declared explicitly if its header is included".

Is this applicable to standard functions? And, what if the definition
is outside the header where the funcY function is defined, and what if
I use it in a source file?

Thanks!
 
E

Eric Sosman

Sensei said:
Hi! I'm concerned about the legality of such a definition:

#define funcX funcY

where funcX belongs to the *standard* C functions. Is it legal to do
this? The standard says "any function declared in a header may be
additionally implemented as a macro defined in the header, so a library
function should not be declared explicitly if its header is included".

The program may fail to compile if the appropriate header
has already #define'd funcX and your funcY does not happen to
match the existing definition perfectly. For example

#include <string.h>
#define strlen my_strlen

may fail, because <string.h> may already contain something like

size_t strlen(const char*); /* ordinary function */
#define strlen _builtin_strlen /* compiler magic */

You could avoid that potential problem:

#include <string.h>
#undef strlen /* just in case */
#define strlen my_strlen
Is this applicable to standard functions?

Yes: the section of the Standard you quoted concerns the
standard library functions.
And, what if the definition is
outside the header where the funcY function is defined, and what if I
use it in a source file?

I'm sorry; I do not understand your questions. In the first
part you seem to be talking of two different kinds of "definition,"
and I'm not sure what each refers to. "Use it in a source file" is
also confusing: First, it's not clear what "it" means, and second,
where but in a source file could you use *any* C construct?
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Eric said:
The program may fail to compile if the appropriate header
has already #define'd funcX and your funcY does not happen to
match the existing definition perfectly. For example

#include <string.h>
#define strlen my_strlen

may fail, because <string.h> may already contain something like

size_t strlen(const char*); /* ordinary function */
#define strlen _builtin_strlen /* compiler magic */

You could avoid that potential problem:

#include <string.h>
#undef strlen /* just in case */
#define strlen my_strlen

That's not allowed in standard C. It's covered by 7.1.3p2:
"No other identiï¬ers are reserved. If the program declares or deï¬nes an
identiï¬er in a context in which it is reserved (other than as allowed by
7.1.4), or deï¬nes a reserved identiï¬er as a macro name, the behavior is
undeï¬ned."
And more practically, defining a macro with the same name as a standard
library function can break other macros which try to call the standard
function.
Yes: the section of the Standard you quoted concerns the
standard library functions.


I'm sorry; I do not understand your questions. In the first
part you seem to be talking of two different kinds of "definition,"
and I'm not sure what each refers to. "Use it in a source file" is
also confusing: First, it's not clear what "it" means, and second,
where but in a source file could you use *any* C construct?

I'm confused as well, the best I can come up with is:

x1.c:
#define printf dummy
extern void printf(void);
int main(void) {
printf();
}

x2.c:
#include <stdio.h>
void dummy(void) {
puts("Hello, world!");
}

If this is meant, I don't see anything disallowing it. It's extremely poor
style, but not invalid.
 
S

Sensei

That's not allowed in standard C. It's covered by 7.1.3p2:
"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."
And more practically, defining a macro with the same name as a standard
library function can break other macros which try to call the standard
function.

Can you clarify the statement above? Read next:
I'm confused as well, the best I can come up with is:

x1.c:
#define printf dummy
extern void printf(void);
int main(void) {
printf();
}

x2.c:
#include <stdio.h>
void dummy(void) {
puts("Hello, world!");
}

If this is meant, I don't see anything disallowing it. It's extremely poor
style, but not invalid.

Yes, That's what I meant, using the #define inside a source file just
the way you wrote. I know it's poor, but it's what I found :)

Clarifying my concerns, I have a non standard C library that hasn't all
the functions it should, in the example code I found that since, for
instance, they have no printf or strlen, they use precompiler magic:

#include <stdio.h>

#define printf _sdk_PRINT_TO_FOO
#define strlen _sdk_STRING_LENGTH_BAR

int main(void)
{
printf("Hello, world!\n");
return 0;
}

The #defines are *inside* the application code, not in the libc. The
(pseudo)libc code has _sdk_PRINT_TO_FOO and _sdk_STRING_LENGTH_BAR
correclty (I hope) working though. I found this source quite weird, and
I didn't know about the legality of such definitions.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Sensei said:
Clarifying my concerns, I have a non standard C library that hasn't all
the functions it should, in the example code I found that since, for
instance, they have no printf or strlen, they use precompiler magic:

#include <stdio.h>

#define printf _sdk_PRINT_TO_FOO
#define strlen _sdk_STRING_LENGTH_BAR

int main(void)
{
printf("Hello, world!\n");
return 0;
}

The #defines are *inside* the application code, not in the libc. The
(pseudo)libc code has _sdk_PRINT_TO_FOO and _sdk_STRING_LENGTH_BAR
correclty (I hope) working though. I found this source quite weird, and
I didn't know about the legality of such definitions.

That's not allowed in standard C, but since your implementation isn't a
conforming one, it's not really relevant what the standard says, just what
works. It would probably be a good idea to hide that in a
#ifndef __STDC__ / ... / #endif
block, though.
 
K

Keith Thompson

Eric Sosman said:
The program may fail to compile if the appropriate header
has already #define'd funcX and your funcY does not happen to
match the existing definition perfectly. For example

#include <string.h>
#define strlen my_strlen

may fail, because <string.h> may already contain something like

size_t strlen(const char*); /* ordinary function */
#define strlen _builtin_strlen /* compiler magic */

A quibble: if <string.h> defined strlen as a macro, it must be a
function-like macro, such as:
#define strlen(s) _builtin_strlen(s)
so that a program can call
(strlen)(s)
to call the actual function.
 
S

Sensei

That's not allowed in standard C, but since your implementation isn't a
conforming one, it's not really relevant what the standard says, just what
works. It would probably be a good idea to hide that in a
#ifndef __STDC__ / ... / #endif
block, though.

So, to make the library more standard-adherent I have to modify its
code to provide the ISO functions myself by any allowed means. Is that
right?
 
S

Sensei

A quibble: if <string.h> defined strlen as a macro, it must be a
function-like macro, such as:
#define strlen(s) _builtin_strlen(s)
so that a program can call
(strlen)(s)
to call the actual function.

Keith, a code like the following

#include <stdio.h>

#define printf _sdk_PRINT_TO_FOO
#define strlen _sdk_STRING_LENGTH_BAR

int main(void)
{
printf("Hello, world!\n");
return 0;
}

is illegal, right? See the post from Harald van Dijk.

Thanks to anyone!
 
K

Keith Thompson

Sensei said:
Keith, a code like the following

#include <stdio.h>

#define printf _sdk_PRINT_TO_FOO
#define strlen _sdk_STRING_LENGTH_BAR

int main(void)
{
printf("Hello, world!\n");
return 0;
}

is illegal, right? See the post from Harald van Dijk.

Yes, I think so, but that's not what I was talking about.

A program may not define strlen as a macro, but the implementation
(particularly the <string.h> header) is permitted to do so.
 
J

Jordan Abel

2006-08-21 said:
A quibble: if <string.h> defined strlen as a macro, it must be a
function-like macro, such as:
#define strlen(s) _builtin_strlen(s)
so that a program can call
(strlen)(s)
to call the actual function.

I think it's allowed to #define strlen _builtin_strlen, provided that
_builtin_strlen is itself a real function
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Sensei said:
So, to make the library more standard-adherent I have to modify its
code to provide the ISO functions myself by any allowed means. Is that
right?

That's not what I meant, but yes, modifying the library may be another
possibility. What I meant was closer to what you originally said: keep the
#defines in the application code, except in such a way that they don't work
anymore when you switch to a conforming implementation.
 
S

Sensei

Yes, I think so, but that's not what I was talking about.

A program may not define strlen as a macro, but the implementation
(particularly the <string.h> header) is permitted to do so.

My concerns is about the ISO compatibility of the statements above, and
wasn't strictly related to strlen or printf, but to all the functions
belonging to the standard.
 
K

Keith Thompson

Jordan Abel said:
I think it's allowed to #define strlen _builtin_strlen, provided that
_builtin_strlen is itself a real function

I suppose so, but there wouldn't be much point. The implementation
could just change the name of the function from "_builtin_strlen" to
"strlen".

Unless "_builtin_strlen" is some externally defined function that
happens to implement strlen() correctly, but the author of the header
doesn't have the ability to rename it.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Jordan said:
I think it's allowed to #define strlen _builtin_strlen, provided that
_builtin_strlen is itself a real function

It's not. You're guaranteed that stringising strlen produces "strlen" (as
long as it is not followed by an opening parenthesis).
 
K

Keith Thompson

Harald van Dijk said:
It's not. You're guaranteed that stringising strlen produces "strlen" (as
long as it is not followed by an opening parenthesis).

Where (and why) is that guaranteed?
 
C

Clark S. Cox III

Harald said:
It's not. You're guaranteed that stringising strlen produces "strlen" (as
long as it is not followed by an opening parenthesis).

Where do you see that guarantee?
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Keith said:
Where (and why) is that guaranteed?

By the same reason stringising xxx is guaranteed to produce "xxx": the
absense of any permission to implement it as an object-like macro. It was
mainly meant to show that the as-if rule doesn't apply. I would also be
surprised if the below code is not meant to be strictly conforming:

struct {
int strlen;
} s;
#include <string.h>
int main(void) { return s.strlen; }
 
K

Keith Thompson

Harald van Dijk said:
By the same reason stringising xxx is guaranteed to produce "xxx": the
absense of any permission to implement it as an object-like macro. It was
mainly meant to show that the as-if rule doesn't apply. I would also be
surprised if the below code is not meant to be strictly conforming:

struct {
int strlen;
} s;
#include <string.h>
int main(void) { return s.strlen; }

I'm not entirely sure about the stringizing argument, but I find your
example much more convincing.
 
R

Richard Bos

Jordan Abel said:
I think it's allowed to #define strlen _builtin_strlen, provided that
_builtin_strlen is itself a real function

I don't think so. From [7.1.4]:

# Any function declared in a header may be additionally implemented as a
# function-like macro defined in the header,

Explicit mention is made of a function-like macro; no mention at all of
an object-like one; and from the same paragraph:

# Any macro definition of a function can be suppressed locally by
# enclosing the name of the function in parentheses,

Since a strictly conforming program _can_ tell the difference (using the
stringising trick at the very least), IMO a strict reading of that
paragraph disallows #defining a library function as an object-like
macro.

Richard
 
K

Keith Thompson

Jordan Abel said:
I think it's allowed to #define strlen _builtin_strlen, provided that
_builtin_strlen is itself a real function

I don't think so. From [7.1.4]:

# Any function declared in a header may be additionally implemented as a
# function-like macro defined in the header,

Explicit mention is made of a function-like macro; no mention at all of
an object-like one; and from the same paragraph:

# Any macro definition of a function can be suppressed locally by
# enclosing the name of the function in parentheses,

Since a strictly conforming program _can_ tell the difference (using the
stringising trick at the very least), IMO a strict reading of that
paragraph disallows #defining a library function as an object-like
macro.

Even if it were legal, <string.h> declaring strlen as an object-like
macro would be pointless. If you hae
#define strlen __builtin_strlen
(where __builtin_strlen would be the name of a function that does the
same thing), there *still* has to be a real function named "strlen",
because a program can do this:
#undef strlen
... strlen(whatever) ...

But the best argument I've seen is the code sample posted by Harald
van D??k (sorry, I'm having trouble entering accented characters):

| struct {
| int strlen;
| } s;
| #include <string.h>
| int main(void) { return s.strlen; }

If <string.h> defined strlen as an object-like macro, this strictly
conforming code would fail.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top