Can I redefine a macro with another #define directive? - c

I want to redefine the value of a macro constant with another value. Now I know the technique of using #undef and thereafter re-#define the macro itself, like:
#define LEN_OSG 59
....
#undef LEN_OSG
#define LEN_OSG 70
I´d attempt to abbreviate this and discovered that it is possible to redefine the macro constant by just another #define directive:
#define LEN_OSG 59
....
#define LEN_OSG 70
Example program:
#include <stdio.h>
#define LEN_OSG 59
int main()
{
printf("LEN_OSG is %d.\n",LEN_OSG);
#define LEN_OSG 70
printf("LEN_OSG is %d.",LEN_OSG);
}
Of course, Both gcc and clang give me the warnings:
warning: "LEN_OSG" redefined. (gcc)
and
warning: 'LEN_OSG' macro redefined [-Wmacro-redefined] (clang)
but they do compile it (without the -Werror option of course) and give both the correct result:
Execution build compiler returned: 0
Program returned: 0
LEN_OSG is 59.
LEN_OSG is 70.
My questions:
Can I redefine a macro with another #define directive by ignoring this specific warning?
Does this in any kind involve undefined behavior or cause a potential harm to the program?
Thank you very much.

Redefining a macro (when the redefintion is not the same) is a constraint violation. The constraint is spelled out in sectino 6.10.3p2 of the C standard:
An identifier currently defined as an object-like macro shall
not be redefined by another #define preprocessing directive unless
the second definition is an object-like macro definition and
the two replacement lists are identical. Likewise, an
identifier currently defined as a function-like macro shall
not be redefined by another #define preprocessing directive
unless the second definition is a function-like macro
definition that has the same number and spelling of parameters,
and the two replacement lists are identical.
And section 4p2 states the following about constraint violations:
If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside
of a constraint or runtime-constraint is violated, the
behavior is undefined. Undefined behavior is otherwise indicated
in this International Standard by the words ‘‘undefined
behavior’’ or by the omission of any explicit definition of
behavior. There is no difference in emphasis among these three; they
all describe ‘‘behavior that is undefined’’.
So redefining a macro invokes undefined behavior. You must use #undef if you want to redefine the macro.

You should really get used to using #undef before re-defining a macro! Most compilers will generate a warning; however, according to the C99 Standard (and also the C18 Standard - the paragraphs are the same in both):
6.10.3 Macro replacement ...
2 An identifier currently defined as an object-like macro shall not be redefined by another #define preprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical. Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.
The 'replacement lists' for the LEN_OSG (object-like) macro in your example are 59 and then 70 - which are not identical.

Related

Does non-reserved identifier at translation phase 4 make it impossible to reserve a file scope identifier at translation phase 7?

Consider this code:
/*
* stdio.h
*
* note: it is an example of a particular implementation of stdio.h
* containing _x; it is not "my code added to stdio.h"
*/
void _x(void);
/* t627.c */
#define _x 0
#include <stdio.h>
Invocation:
$ gcc t627.c
t627.c:1:12: error: expected identifier or ‘(’ before numeric constant
1 | #define _x 0
| ^
stdio.h:1:6: note: in expansion of macro ‘_x’
1 | void _x(void);
At translation phase 4 the identifier _x is non-reserved. At translation phase 7 the identifier _x is reserved (for use as identifier with file scope in both the ordinary and tag name spaces). Since translation phase 4 precedes translation phase 7, then at translation phase 7 the identifier _x (currently defined as a macro name) is already replaced by its replacement list 0, invalidating the program.
Does it mean that in cases when the user-defined macro (that begins with an underscore, followed by a lowercase letter) can collide/overlap with the file scope identifier with the same name, such file scope identifier cannot be reserved?
#define macros are always a textual substitution.
Headers, of course, are not compiled entities in their own right, so are only evaluated at the point they are #included.
Let's say you have a header containing a certain non-macro identifier*.
In a C module, you #define that same identifier to expand to something arbitrary and pathological, and then #include the header
Since the compiler encounters the #define before it encounters the #include, all mentions in the header of the colliding identifier will be substituted with the macro's expansion. The consequences can be (and often are) disastrous, or at the very least hard to debug.
It doesn't really matter whether or not the identifier starts with an underscore. If you wrote #define printf scanf, just for instance, that would cause chaos!
(* I stipulate "non-macro" just to avoid the complications of what would happen if the header redefined - or tried to - the macro you defined first.)
You're not allowed to define macros with any of the reserved names. This is stated explicitly in section 7.1.3p2 of the C standard:
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.
(Boldface: my emphasis.)
To put it another way, every identifier that is reserved in some phase-7 context is also reserved for use as a macro name.
Found a relevant quote from P.J. Plauger (emphasis added):
Remember that the user can write macros that begin with an underscore, followed by a lowercase letter. These names overlap those reserved to the implementor for naming external functions and data objects.
So, the answer seems to be "yes".

Macro definition stored by preprocessor

Shouldn't I be getting warning or error message after declaring macro in this way:
#define c 123
#define a b
#define b c
The code worked flawlessly - so just like variable definition, is macro definition stored somewhere?
This is perfectly fine, because preprocessor does not act upon macro definitions until the point of expansion. That is why the order does not matter: as long as each macro has a definition to which it could be expanded when your code makes a reference to it, the preprocessor is happy. This applies to macros that rely on other macros for their expansion.
One consequence of this behavior is that the relative order of macro declarations does not change the end result.

Can the parameter names in a C macro have side effects from previous definitions?

I know about the argument prescan when an argument is used in a C macro, but that happens when you use an already defined macro. However, when you define it, do you need to have any special care at choosing the parameter names? Does the preprocessor parse the macro in an "atomic" way so that parameter names are not expanded?
I mean, imagine this scenario:
#define MYVAL {is this safe?}
#define ADDVALUES(MYVAL,YOURVAL) do{(MYVAL)+(YOURVAL);}while(0)
int val=ADDVALUES(1,3);
How is the ADDVALUES macro parsed? Is MYVAL expanded before defining the ADDVALUES macro?
I have not read any warning about choosing the parameter names in a macro, so I tend to believe their name is not expanded before the macro is parsed (I have read warnings about naming local variables in macros, about the macros names themselves, about swallowing the semicolon, etc., but nothing about choosing the parameter names).
The scope of the parameter MYVAL is distinct from that of the object-like macro MAYVAL. Quoting from the relevant part of the Standard, 6.10.3,p10:
The parameters are specified by the optional list of identifiers,
whose scope extends from their declaration in the identifier list
until the new-line character that terminates the #define preprocessing
directive.
The last line in the example given will be expanded as
int val=do{(1)+(3);}while(0);
I tried with gcc 4.8.5
#define NV1 a
#define V1(NV1) b NV1
V1(foo)
gcc -E test.h
Result
b foo
So parameter name is not expanded as a macro and overrides the earlier conflicting definition

Check if a constructed constant is #define'd

I am trying to build a test that checks if a certain file defines a header guard with a certain namespace. Because the test is generic, this namespace is only known at compile-time and passed in as -DTHENAMESPACE=BLA. We then use some magic from https://stackoverflow.com/a/1489985/1711232 to paste that together.
This means I want to do something like:
#define PASTER(x, y) x##_##y
#define EVALUATOR(x, y) PASTER(x, y)
#define NAMESPACE(fun) EVALUATOR(THENAMESPACE, fun)
#ifndef NAMESPACE(API_H) // evaluates to BLA_API_H
# error "namespace not properly defined"
#endif
But this does not work properly, with cpp complaining about the ifndef not expecting the parentheses.
How can I do this properly, if it is possible at all?
I have also tried adding more layers of indirection, but not with a lot of success.
So directly, properly executing the #ifdef this at least appears to not be possible:
Considering the defined operator:
If the defined operator appears as a result of a macro expansion, the C standard says the behavior is undefined. GNU cpp treats it as a genuine defined operator and evaluates it normally. It will warn wherever your code uses this feature if you use the command-line option -Wpedantic, since other compilers may handle it differently. The warning is also enabled by -Wextra, and can also be enabled individually with -Wexpansion-to-defined.
https://gcc.gnu.org/onlinedocs/cpp/Defined.html#Defined
and ifdef expects a MACRO, and does not do further expansion.
https://gcc.gnu.org/onlinedocs/cpp/Ifdef.html#Ifdef
But maybe it is possible to trigger an 'undefined constant' warning (-Wundef), which would also allow my test pipeline to catch this problem.
If we assume that include guards always looks like
#define NAME /* no more tokens here */
and if, as you said, any compile time error (rather than #error exclusively) is acceptable, then you can do following:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) static int CAT(UNUSED_,__LINE__) = CAT(CAT(THENAMESPACE,CAT(_,x)),+1);
NAMESPACE(API_H)
Here, NAMESPACE(API_H) tries to concatenate BLA_API_H and + using ##.
This results in error: pasting "BLA_API_H" and "+" does not give a valid preprocessing token except if BLA_API_H is #defined to 'no tokens'.
In presence of #define BLA_API_H, NAMESPACE(API_H) simply becomes
static int UNUSED_/*line number here*/ = +1;
If you settle for a less robust solution, you can even get nice error messages:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define TRUTHY_VALUE_X 1
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) CAT(CAT(TRUTHY_VALUE_,CAT(THENAMESPACE,CAT(_,x))),X)
#if !NAMESPACE(API_H)
#error "namespace not properly defined"
#endif
Here, if BLA_API_H is defined, then #if !NAMESPACE(API_H) expands to #if 1.
If BLA_API_H is not defined, then it expands to #if TRUTHY_VALUE_BLA_API_HX, and TRUTHY_VALUE_BLA_API_HX evaluates to false due to being undefined.
The problem here is that if TRUTHY_VALUE_BLA_API_HX accidentally turns out to be defined to something truthy, you'll get a false negatie.
I don't think that macro expansion inside #ifndef directive is possible in the realm of standard C.
#ifndef symbol is equivalent of #if !defined symbol. Standard says this about it (§6.10.1 Conditional inclusion):
... it may contain unary operator expressions of the form
defined identifier
or
defined ( identifier )
and
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary
operator), just as in normal text. If the token defined is generated as a result of this replacement
process or use of the defined unary operator does not match one of the two specified forms prior to
macro replacement, the behavior is undefined. ...
So basically identifiers in defined expression are not expanded, and your current NAMESPACE(API_H) is not valid form of identifier.
Possible workaround could be to simply use:
#if NAMESPACE(API_H) == 0
# error "namespace not properly defined"
#endif
This works because non-existing identifiers are replaced with 0. Problem with this approach is that there will be false error if BLA_API_H is defined as 0, but depending on your situation that may be acceptable.
You can also do this using preprocessor pattern matching.
#define PASTE3(A,B,C) PASTE3_I(A,B,C)
#define PASTE3_I(A,B,C) A##B##C
#define PASTE(A,B) PASTE_I(A,B)
#define PASTE_I(A,B) A##B
#define THIRD(...) THIRD_I(__VA_ARGS__,,,)
#define THIRD_I(A,B,C,...) C
#define EMPTINESS_DETECTOR ,
#if THIRD(PASTE3(EMPTINESS_,PASTE(THENAMESPACE,_API_H),DETECTOR),0,1)
# error "namespace not properly defined"
#endif
This is the same idea as #HolyBlackCat's answer except that it's done in the preprocessor; the inner paste in the expression in the #if directive generates a token based on THENAMESPACE, pasting it to your required _API_H. If that token itself is defined in a macro, it will expand to a placemarker during the PASTE3 operation; this effectively pastes EMPTINESS_ [placemarker] DETECTOR, which is a macro expanding to a comma. That comma will shift the arguments of the indirect THIRD, placing 0 there, making the conditional equivalent to #if 0. Anything else won't shift the arguments, which results in THIRD selecting 1, which triggers the #error.
This also makes the same assumption HolyBlackCat's answer makes... that inclusion guards always look like #define BLA_API_H, but you can accommodate specific alternate styles using expanded pattern matching... for example, if you want to accept inclusion guards like #define BLAH_API_H 1 (who does that?), you could add #define EMPTINESS_1DETECTOR ,.
The language defines no way other than use of the defined operator or an equivalent to test whether identifiers are defined as macro names. In particular, a preprocessor directive of the form
#ifndef identifier
is equivalent to
#if ! defined identifier
(C11, 6.10.1/5). Similar applies to #ifdef.
The defined operator takes a single identifier as its operand, however, not an expression (C11, 6.10.1/1). Moreover, although the expression associated with an #if directive is macro expanded prior to evaluation, the behavior is undefined if in that context macro expansion produces the token "defined", and macro names modified by the defined unary operator are explicitly excluded from expansion (C11, 6.10.1/4).
Thus, although it is possible in many contexts to construct macro names via token pasting, and in such contexts the results are thereafter be subject to macro expansion, the operand of a defined operator is not such a context. The language therefore defines no way to test whether a constructed or indirectly-specified identifier is defined as a macro name.
HOWEVER, you can avoid relying on defined if you are in control of all the header guards, and you are willing to deviate slightly from traditional style. Instead of merely #defineing your header guards, define them to some nonzero integer value, say 1:
#if ! MYPREFIX_SOMEHEADER_H
#define MYPREFIX_SOMEHEADER_H 1
// body of someheader.h ...
#endif
You can then drop the defined operator from your test expression:
#if ! NAMESPACE(API_H)
# error "namespace not properly defined"
#endif
Do note, however, that the #define directive has a similar issue: it defines a single identifier, which is not subject to prior macro expansion. Thus, you cannot dynamically construct header guard names. I'm not sure whether you had that in mind, but if you did, then all the foregoping is probably moot.

Using #undef before #define

In many places I see the usage of undefine macro before defining the same macro. For example:
#undef FORMULA
#ifdef SOMETHING
#define FORMULA 1
#else
#define FORMULA 2
#endif
What for the #undefine FORMULA used?
I may guess that it deals with the case when the macro was already defined before. But isn't the new definition overrides the old one? Thanks!
A macro name currently defined cannot be redefined with a different definition (see below), so #undef allows that macro name to be redefined with a different definition.
Here's the relevant legalese:
Both C and C++ Standards (same wording):
A macro definition lasts (independent of block structure) until a corresponding #undef directive is encountered or (if none is encountered) until the end of the preprocessing translation unit.
Slight differences in wording, same meaning:
C Standard (N1256), §6.10.3/2:
An identifier currently defined as an object-like macro shall not be redefined by another #define preprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical. Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.
C++ Standard (N3337) §16.3/2
An identifier currently defined as an object-like macro may be redefined by another #define preprocessing directive provided that the second definition is an object-like macro definition and the two replacement lists are identical, otherwise the program is ill-formed. Likewise, an identifier currently defined as a function-like macro may be redefined by another #define preprocessing directive provided that the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical, otherwise the program is ill-formed.
Same wording in both Standards:
Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, ordering, spelling, and white-space separation, where all white-space separations are considered identical.
So:
#define X(y) (y+1)
#define X(z) (z+1) // ill-formed, not identical
IMHO, using #undef is generally dangerous due to the scoping rules for preprocessor macros. I'd prefer to get a warning or error from the preprocessor and come up with a different preprocessor macro rather than have some translation unit silently accept a wrong macro definition that introduces a bug into the program. Consider:
// header1.h
#undef PORT_TO_WRITE_TO
#define PORT_TO_WRITE_TO 0x400
// header2.h
#undef PORT_TO_WRITE_TO
#define PORT_TO_WRITE_TO 0x410
and have a translation unit #include both headers. No warning, probably not the intended result.
Yes, the new definition overrides all previous. But there is corresponding warning message. With #undef you have no warnings.
But isn't the new definition overrides the old one?
Yes, it does (when your compiler allows it). However, redefining a macro results in a compiler warning, which using #undefine lets you avoid.
This may be important in programming shops with strict rules on compiler warnings - for example, by requiring all production code to be compiled with -Werror flag, which treats all warnings as errors.
#undef removes the macro, so the name is free to be defined again.
If the macro was never defined in the first place, #undef has no effect, so there's no downside. #undef … #define should be read as replacing any potential previous definition, but not to imply that it must already be defined.
Popular compilers do allow you to skip the #undef, but this is not allowed by the official standard ISO C and C++ language specifications. It is not portable to do so.

Resources