2017-01-13 6 views
1

Переменная 'a' не разрешается макросом препроцессора, если функция fun() определена выше main(), но работает нормально, если определено ниже main().Переменная необъявленная ошибка при использовании внутри функции

#include <stdio.h> 

void fun() 
{ 
    printf("%d",a); 
} 

int main() 
{ 
    #define a 5 
    fun(); 
    return 0 ; 
} 

В чем причина этого? И как мы можем заставить его работать, чтобы мне не пришлось переместить определение функции fun().

+0

Компилятор читает сверху вниз, поэтому в грубых выражениях необходимо увидеть определение 'a' перед его использованием. Переместите '# define 5' перед' fun() '. – Peter

+5

'a' не является переменной. Пожалуйста, прочитайте, как работает препроцессор и что делает '# define'. – Olaf

+1

И даже если 'a' является переменной, прочитайте о сфере видимости переменных. Все, что вы определяете в 'main', не отображается в' fun'. – Gerhardh

ответ

5

С препроцессора работает сверху вниз и заменяет #define с («текст замены»). Итак, когда #define a 5 в main(), он не может «вернуться» и заменить a на func(); он может заменить только a, если таковые имеются, ниже его #define.

Вам просто нужно определить его выше func().

От C11 draft, 6.10.3 Macro replacement:

предварительной обработки директивы формы

# define identifier replacement-list new-line 

определяет объект-подобный макрос, который вызывает каждый последующий экземпляр макро имя), чтобы быть заменяется на замену списка токенов предварительной обработки, которые составляют остаток от dir ective. Затем список замещения повторно сканируется для большего количества имен макросов , как указано ниже.

Это было то же, что предварительно стандартным С. Из Dennis Ritchie's C Reference Manual:

12,1 Токена замены Компиляторов-линия управления формы

# определить идентификатор маркера строка

(примечание: нет конечной точки с запятой) заставляет препроцессор заменить последующие экземпляры идентификатора с заданной строкой токенов (за исключением линий управления компиляторами). В заменяющей токеновой строке есть комментарии, удаленные из нее, и она окружена пробелами. Нет попытка повторного сканирования заменяемой строки.

(акцент мой).

3

Препроцессор заменит любые экземпляры a на 5 после определения точки макроса. Вы можете поместить строку #define над функцией fun.

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

void fun() 
{ 
    printf("%d", 5); 
} 
3

Шаг предварительной обработки выполняется до этапа компиляции. Более того, препроцессор не знает C; для препроцессора исходный файл - это просто текст.

В вашем примере символ a, используемый в функции fun(), не был объявлен перед использованием, что является ошибкой. Не имеет значения, что где-то еще ниже есть определение препроцессора для a. Поскольку определение еще ниже, оно не применяется в теле fun(): всегда помните, что для пропроцессора исходный файл представляет собой просто текст, он не знает C. Директивы предварительной обработки применяются в том месте, где они появляются в тексте, никогда ранее ,

4

Конечно, вы не можете ссылаться на макрос препроцессора, прежде чем определять его, это просто не так, как он работает.

Здесь нет «переменной», ваше использование слова очень сбивает с толку. Препроцессор просто выполняет замену текста, компилятор никогда не увидит символ a, вместо этого он увидит 5 (если макрос был определен).

Я не знаю, как «заставить его работать», так как цель очень странная. Если вы хотите получить доступ к глобальной переменной, используйте один:

#include <stdio.h> 

int fun(int x) 
{ 
    extern int a; 
    return a + x; 
} 

int a = 12; 

int main(void) { 
    printf("a=%d, fun() returned %d\n", a, fun(11)); 
    return 0; 
} 

Здесь extern заставляет нас уйти с определением a после fun(), но она не может быть внутри main().

+0

Ooof. Это потенциально какой-то извращающий код. Не уверен, что я должен поздравить вас с приходом этого злого кода или нет. ;-) –

+0

@AndrewHenle Это? Возможно ... не очень распространенная картина, поскольку она пытается удовлетворить случайное требование не переупорядочивать вещи. – unwind

+0

Да, я думаю, что это не только необычный шаблон, он будет путать любого, не зная, что ключевое слово 'extern' изменяет определение в декларации, что, вероятно, и, к сожалению, довольно значительное число разработчиков. Так что это просто злой способ взорвать таких разработчиков, это блестяще. :-D –

Смежные вопросы