Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

#define and #include order in C

I've following code which I compile with gcc

#include<stdio.h>
#include<stdbool.h>
#define true 9
int main() { 
   printf("TRUE = %d\n",true);
   return 0;
}

And I get Error

test.c:3:0: warning: "true" redefined [enabled by default]
In file included from test.c:2:0:
/usr/lib/gcc/x86_64-linux-gnu/4.7/include/stdbool.h:34:0: note: this is the location of the previous definition

But when I alter the code a bit

#include<stdio.h>
#define true 9
#include<stdbool.h>
int main() { 
   printf("TRUE = %d\n",true);
   return 0;
}

Output:

TRUE = 1

Question:

I understand the reason for error in first case but In second case when I define true before I #include<stdbool.h>, why is it allowed to redefine true?

Update:

Here is stdbool.h.

First few lines are

#ifndef _STDBOOL_H
#define _STDBOOL_H

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

which is nothing like in the Yu Hao 's answer .

like image 429
TheKojuEffect Avatar asked Sep 23 '13 11:09

TheKojuEffect


2 Answers

In the file stdbool.h, the code may look like this:

#ifdef true
#undef true
#define true 1
#endif

You should do the same when the macro may be defined before. Another similar trick is like this:

#ifndef MAGIC
#define MAGIC 42
#endif

EDIT

Turns out this is gcc's feature, see @alk's answer for detail.

All warnings, other than those generated by ‘#warning’, are suppressed while GCC is processing a system header. Macros defined in a system header are immune to a few warnings wherever they are expanded.

like image 137
Yu Hao Avatar answered Nov 14 '22 20:11

Yu Hao


Although Yu Hao gave a possible answer to the question, things indeed are different here.

This easily could be proved by looking into stdbool.h to realise that there is no #ifdef ... #endif "guard" around the definition of true.

Moreover gcc does simply surpress warnings that whould be given for issues in system headers*1.

Use the gcc's option -isystem to make the 1st example behave like the 2nd.

From the gcc manual:

The header files declaring interfaces to the operating system and runtime libraries often cannot be written in strictly conforming C. Therefore, GCC gives code found in system headers special treatment. All warnings, other than those generated by ‘#warning’ (see Diagnostics), are suppressed while GCC is processing a system header. Macros defined in a system header are immune to a few warnings wherever they are expanded. This immunity is granted on an ad-hoc basis, when we find that a warning generates lots of false positives because of code in macros defined in system headers.

[...]

The -isystem command line option adds its argument to the list of directories to search for headers, just like -I. Any headers found in that directory will be considered system headers.


*1: System headers are headers included in <> brackets.

like image 7
alk Avatar answered Nov 14 '22 18:11

alk