2015-07-06 6 views
0

Хотелось бы спросить вас, почему в следующем коде компилятор не дает ошибку? Это файл flash.h:Ошибка компилятора при использовании макросов, которые ранее не были определены

#ifndef _FLASH_H_ 
#define _FLASH_H_ 
#define BANK_A 0 
#define BANK_B 1 
#define BANK_C 3 
#define FLASH_IS_BUSY   (FCTL3 & BUSY)//FCTL3 and BUSY are defined in msp430f5438a. 
#endif 

И это файл main.c:

#include "flash.h" 
#include <msp430f5438a.h> 
void main(void) 
{ 
    while(1) 
    { 
     ; 
    } 
} 

Проблема заключается в том, что я не понимаю, как компилятор не выдаст ошибку на этой линии:

#define FLASH_IS_BUSY   (FCTL3 & BUSY) 

Поскольку не существует никакого способа (в соответствии с моим пониманием) компилятором, чтобы знать, что такое FCTL3 и BUSY среднего. Оба эти макросы определены в msp430f5438a.h следующим образом:

#define FCTL3 (*((unsigned char*)0x0144u)) 
#define BUSY 0x01 

Но flash.h включен до того msp430f5438a.h Как компилятор разрешает эти символы: FCTL3 и BUSY?

+1

макросы заменяются на/до времени синтаксического анализа. поэтому компилятор в теории не видит «FCTL3» и «BUSY» – Alex

+0

Компилятор не может предупреждать всех (или даже самых) возможных ошибок. Читайте о [теореме Райса] (https://en.wikipedia.org/wiki/Rice%27s_theorem) и [проблема с остановкой] (https://en.wikipedia.org/wiki/Halting_problem) –

ответ

3

Дело здесь в том, что #define s работает как текстовая замена на этапе предварительной обработки, они не совпадают с объявлением или определением переменной.

В вашем файле заголовка вы определили только MACRO FLASH_IS_BUSY, но в коде вы его не использовали. Даже если вы использовали это, до main(), заголовок #include <msp430f5438a.h> есть, что делает определение FCTL3 и BUSY доступным вашему коду, если используется.

TL; DRFLASH_IS_BUSY макро определение в файле заголовка не требуется FCTL3 и BUSY быть определены уже. Например, вы можете указать эти значения MACRO с помощью опции -D с gcc, они не обязательно должны отображаться в коде.

Тем не менее, рекомендуется подпись main() является int main(void)

+1

msp430 - это микроконтроллер, поэтому 'int main (void)', скорее всего, неправильный и плохой. – Lundin

+0

@ Lundin Huh? 'int main (void)' является одной из сигнатур, требуемых стандартом C. Микроконтроллер не имеет командной строки, поэтому 'int main (void)' в чем смысл, другая альтернатива - 'int main (int, char * *) '. – Potatoswatter

+0

@ Lundin sir, в свою защиту я бы хотел поднять два очка. 1) вопрос не был помечен как 'msp430' или такой, но только с' C' и 2) _case_ в вопросе не имеет прямого отношения к этому, поэтому тег также не требуется, последняя строка была всего лишь предложением, для стандартов С. Это все. Надеюсь, я не ошибаюсь.:-) –

1

Вы не воспользовались FLASH_IS_BUSY, поэтому препроцессор не заменит неправильный синтаксис.

Кстати, будьте осторожны с написанием while(1); в старых стандартах C (и более новых стандартах на C++), так как поведение вашей программы не определено.

См Is while(1); undefined behavior in C?

+0

Сэр, как с бесконечным циклом вызывается UB? Я понимаю часть _useless_, но как это UB? –

+2

Это хорошо известная техничность. Если в теле цикла было «printf» или что-то подобное, тогда все было бы хорошо. – Bathsheba

+0

Простите, сэр, я все равно вас не достал. Может быть, вы можете указать мне на какую-то ссылку, где я могу больше узнать об этом (если не спрашивать слишком много)? Заранее спасибо. :-) –

2

Ограничение по конкретной теме вашего вопроса (препроцессора замен), с этим:

#define FLASH_IS_BUSY (FCTL3 & BUSY) 

Вы не используете FCTL3 и BUSY каким-либо образом. Вы просто инструктируете компилятор выполнить текстовую замену. Ему не нужно ничего знать о них.

Однако при использовании его в коде, как это:

int flags = FLASH_IS_BUSY; 

Он будет выполнять первую замену:

int flags = (FCTL3 & BUSY); 

Замена цикл будет продолжаться до тех пор, пока что-то заменить (или жесткий порог). Если вы забудете включить msp430f5438a.h, то код выше не будет просто компилироваться (потому чтои BUSY неизвестны), однако если вы включили правый заголовочный файл (не имеет значения, в каком порядке: msp430f5438a.h сначала или flash.h), они будут заменены препроцессором с их фактических значениями и вы будете иметь правильный код:

int flags = ((*((unsigned char*)0x0144u)) & 0x01); 

Теперь препроцессор закончил и компилятор (когда оптимизации включены) (возможно !!!) непосредственно заменить flags с буквальным значением.

Примечание:

  • Вашей main() подпись нестандартная. Он должен (для размещенных средах) быть int main(void) или int main(int argc, char* argv[]). См. Также What is the proper declaration of main?. Обратите внимание, что если ваш компилятор разрешает void main(void) подпись, то это не неправильный, но это только нестандартный. Однако Лундинг подчеркнул, что в автономных средах функция main(), согласно стандарту C, подпись полностью определена. См. Его просветительскую должность: Why is the type of the main function in C and C++ left to the user to define?
  • Я понимаю, что while(1) является только иллюстративным (и это не ваш код), но это может быть UB в более ранних спецификациях C. Я не буду повторять здесь эту (длинную) дискуссию, а затем, пожалуйста, обратитесь к Are compilers allowed to eliminate infinite loops? для дальнейших исследований.
  • u суффикс не требуется, в C целые литералы всегда не отрицательны, то u просто избыточен. Однако может быть требуется некоторыми конкретными рекомендациями (например, в критических системах, см. MISRA), чтобы сделать явным (для читателей), что константа предназначена для неотрицательного целого.
  • Ваша пустая петля может быть просто оптимизирована. Компилятор может свободно генерировать код для ;. Various workarounds exists, если вы хотите сделать его переносным.
+0

Не могли бы вы немного рассказать о проблеме (1) (в аспекте стандартных спецификаций до C99)? Что касается того, почему это считается UB? – HighPredator

+0

msp430 - это микроконтроллер, поэтому 'int main (void)', скорее всего, неправильный и плохой. Поскольку это автономная система, 'void main (void)' отлично и 100% стандартно. – Lundin

+0

@ Lundin Я не писал, что это _wrong_, или это _error_, я написал _ «... подпись нестандартная». _. Я подчеркиваю ** нестандартное **, почти каждый компилятор разрешает void main (void), но это ** расширение компилятора **, а не то, что говорит стандарт. Однако то, что произойдет, если вы вернетесь из main() в микроконтроллере, абсолютно не определено. Отпрыгивать? Выполнить мусор? Повесьте? Если у вас есть явное возвращаемое значение, вы (по крайней мере) избавитесь от простых ошибок (например, скопируйте и вставьте код из другой функции), и вы сохраните свою программу _correct_. –

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

  • Нет связанных вопросов^_^