#define и #include порядок в C

У меня есть код, который я компилирую с помощью gcc

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

И я получаю 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

Но когда я немного изменяю код

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

Выход:

TRUE = 1

Вопрос:

Я понимаю причину ошибки в первом случае, но во втором случае, когда я определяю true до я #include<stdbool.h>, почему разрешено переопределять true?

Update:

Вот stdbool.h.

Первые несколько строк

#ifndef _STDBOOL_H
#define _STDBOOL_H

#ifndef __cplusplus

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

который не похож на ответ Yu Hao .

Ответ 1

Хотя Ю Хао дал возможный ответ на вопрос, здесь действительно разные.

Это легко доказать, посмотрев на stdbool.h, чтобы понять, что в определении true нет #ifdef ... #endif "защитника".

Кроме того, gcc просто прикладывает внимание к предупреждениям, которые должны быть заданы для проблем в заголовках системы * 1.

Используйте опцию gcc -isystem, чтобы сделать первый пример, как 2-й.

Из руководства gcc:

Заголовочные файлы, объявляющие интерфейсы для операционной системы и библиотек времени выполнения, часто не могут быть записаны в строго соответствии C. Поэтому GCC дает код, найденный в специальной обработке системных заголовков. Все предупреждения, кроме тех, которые генерируются с помощью '#warning (см. Диагностика), подавляются, а GCC обрабатывает системный заголовок. Макросы, определенные в системном заголовке, защищены от нескольких предупреждений, где бы они ни расширялись. Этот иммунитет предоставляется на разовой основе, когда мы обнаруживаем, что предупреждение генерирует множество ложных срабатываний из-за кода в макросах, определенных в заголовках системы.

[...]

Опция командной строки -системы добавляет свой аргумент в список каталогов для поиска заголовков, как -I. Все заголовки, найденные в этом каталоге, будут считаться заголовками системы.


* 1: Заголовки систем - это заголовки, включенные в скобки <>.

Ответ 2

В файле stdbool.h код может выглядеть следующим образом:

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

Вы должны сделать то же самое, когда макрос может быть определен ранее. Другой подобный трюк выглядит следующим образом:

#ifndef MAGIC
#define MAGIC 42
#endif

ИЗМЕНИТЬ

Оказывается, это функция gcc, см. @alk answer для подробностей.

Все предупреждения, кроме тех, которые генерируются '#warning, подавляются, а GCC обрабатывает системный заголовок. Макросы, определенные в системном заголовке, не защищены от нескольких предупреждений, где бы они ни расширялись.

Ответ 3

Хорошо, ваше предупреждение уже говорит об этом:

test.c:3:0: warning: "true" redefined [enabled by default]

GCC позволяет вам переопределять значения, если вы явно не указали это. Вы можете использовать -Werror для этого.