tags:

views:

261

answers:

4

The title nearly says it all, but I will restate the question...

Is the following program a "strictly conforming program" under the C99 standard?

#include <stdlib.h>
/* Removing any pre-existing macro definition, in case one should exist in the implementation.
 * Seems to be allowed under 7.1.3 para 3, as malloc does not begin with _X where X is any  capital letter.
 * And 7.1.4 para 1 explicitly permits #undef of such macros.
 */
#ifdef malloc    
#undef malloc     
#endif            

/* Macro substitution has no impact on the external name malloc
 * which remains accessible, e.g., via "(malloc)(s)".  Such use of
 * macro substitution seems enabled by 7.1.4 para 1, but not specifically
 * mentioned otherwise.
 */
void * journalling_malloc(size_t size);
#define malloc(s)     ((journalling_malloc)(s))      

int main(void)
{
    return malloc(10) == NULL ? 1 : 0;     
    /* Just for the sake of expanding the 
     * macro one time, return as exit code
     * whether the allocation was performed. 
     */
}
+3  A: 

You will want to change journalling_malloc(...) from void to void *, change the comments to // (because they are commenting out your undef) and add a #endif near the top, but otherwise it looks fine.

DigitalRoss
Good catch, thanks. I had meant it to be something that would compile, and I made the change you suggested. ;)
Heath Hunnicutt
I should add that you don't need to wrap #undef in a conditional. It is OK to #undef something that isn't defined.
DigitalRoss
oh man thanks for being my human compiler. :)
Heath Hunnicutt
+1  A: 

Will it work: Yes.

Is it conformant: No.

According to the C Standard:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

All names in the standard library are reserved (including malloc).

7.1.3 Reserved identifiers
Specifically:  
    <quote>Each macro name in any of the following subclauses</quote>
    <quote>All identifiers with external linkage in any of the
    following subclauses</quote>

Also a strictly conforming program will can not define names that are reserved for the implementation (i.e. This includes reserved names and idnetifiers, those for current libraries and those reserved for future use).

7.1.3 (note 2)
Specifically:
    <quote>If the program declares or defines an identifier in a context in which
    it is reserved or defines a reserved identifier as a macro name,
    the behavior is undefined.</quote>

Thus by definition: defining malloc() is non conformant because it is undefined behavior (Illegal).

Martin York
Does that mean you would say that according to C99, macro names are part of the "ordinary identifier" namespace defined in section 6.2.3, para 1, 4th bullet item? I ask because you seem to be saying that macro names conflict with ordinary identifiers.
Heath Hunnicutt
A: 

Macro identifiers are proper names, and all library identifiers of any kind are forbidden from aliasing to a macro regardless of the linguistic status of macros.

§6.10.3/7

The identifier immediately following the define is called the macro name. There is one name space for macro names.

§7.1.3/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.

§7.1.3/2

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.

Potatoswatter
Do you agree 7.1.3/3 specifies that one would be permitted to #undef malloc? If so, are you saying that the language of 7.1.3/1 would nevertheless render non-conforming any #define malloc regardless of any #undef? Also, you did see that macro names cannot be "identifier with file scope" because 6.2.1/1 makes a specific statement about the linguistic status of macros. (6.2.1 being the "scope of identifier" section, where "file scope" is defined for non-macro-name identifiers.)
Heath Hunnicutt
@Heath: 7.1.3/3 only forbids things ("behavior is undefined") and only refers to all identifiers beginning with underscore, which `malloc` (at least) is not. It is irrelevant that macros aren't identifiers with file scope; 7.1.3/1 **reserves identifiers with file scope** (including `malloc`) **for macros**.
Potatoswatter
But #define does not declare an identifier with file scope, because it does not declare an identifier. You should incorporate 7.1.3/2 into your answer as you first posted it here and that is the real answer. Notably, as I read C89/C90, this is a discrepancy from the previous standard. C99 specifically mentions the use of #define while C89/C90 mentions only the declaration of an external identifier, which a macro name is not. Anyway, mention 7.1.3/2 as you did in your deleted comment and I will accept your answer as correct. It is 7.1.3/2 that makes it so. I see another answer has it,u1st
Heath Hunnicutt
@Heath: 6.10.3 above clearly says that `#define` does create an identifier. 7.20.3.3 clearly says that `malloc` is an external identifier. Anyway, I'll add 7.1.3/2 if you want.
Potatoswatter
Potatoswatter, yes, you are correct I should not have written that #define does not create an identifier, I meant that it does not create an external identifier. Anyway, it seems the C99 standard really does disallow such a useful part of the language, to my surprise.
Heath Hunnicutt
+8  A: 

Let's look at what the C99 standard has to say about it:

See 7.1.3, §1, clause 5:

Each identifier with file scope listed in any of the following subclauses [...] 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.

As you include stdlib.h, the name malloc is reserved for use as a macro name.

But 7.1.4, §1 allows using #undef on reserved names:

The use of #undef to remove any macro definition will also ensure that an actual function is referred to.

This makes it possible to re-#define malloc, which results in undefined behaviour according to 7.1.3, §2:

If the program [...] defines a reserved identifier as a macro name, the behavior is undefined.

Why does the standard make this restriction? Because other functions of the standard library may be implemented as function-like macros in terms of the original function, so hiding the declaration might break these other functions.

In practice, you should be fine as long as your definition of malloc satisfies all provisions the standard provides for the library function, which can be achieved by wrapping an actual call to malloc().

Christoph
Good reading skills! If you don't mind, may I ask whether you can find the same answer for C89 and augment your answer here? If you would, I will change the title of this question. Such would make it a better resource. Up to you.
Heath Hunnicutt
@Heath: section 4.1.2 of the ANSI draft isn't very detailed, but it says that "All external identifiers declared in any of the headers are reserved, whether or not the associated header is included."; footnote 87 basically implies the same semantics as C99 for this use case
Christoph
btw: you can make the program conforming by not including `stdlib.h` and declaring `malloc()` yourself, which is explicitly allowed by 7.1.4 §2
Christoph