Могу ли я переопределить макрос с помощью другой директивы #define? - PullRequest
2 голосов
/ 10 марта 2020

Я хочу переопределить значение макро константы с другим значением. Теперь я знаю технику использования #undef, а затем повторно #define сам макрос, например:

#define LEN_OSG 59
....
#undef LEN_OSG
#define LEN_OSG 70

Я попытался бы сократить это и обнаружил, что возможно для переопределения макроконстанты с помощью другой директивы #define:

#define LEN_OSG 59
....
#define LEN_OSG 70

Пример программы :

#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);
}

Конечно, оба g cc и clang выдают мне предупреждения:

предупреждение: "LEN_OSG" переопределено. (g cc)

и

предупреждение: макрос 'LEN_OSG' переопределен [-Wmacro-переопределен] (clang)

но они компилируют его (без опции -Werror, конечно) и дают оба правильных результата:

Execution build compiler returned: 0
Program returned: 0
LEN_OSG is 59.
LEN_OSG is 70.

Мои вопросы:

  • Могу ли я переопределить макрос с другим Директива #define, игнорируя это заданное c предупреждение?
  • Влечет ли это какое-либо неопределенное поведение или может нанести вред программе?

Большое спасибо.

Ответы [ 2 ]

2 голосов
/ 10 марта 2020

Переопределение макроса (когда переопределение не совпадает) является нарушением ограничения . Ограничение прописано в разделе 6.10.3p2 C стандарта :

Идентификатор, определенный в настоящее время как объектоподобный макрос, не должен переопределяться другая #define директива предварительной обработки, если второе определение не является объектно-подобным определением макроса и два списка замены идентичны. Аналогично, идентификатор, в настоящее время определяемый как функционально-подобный макрос, не должен быть переопределен другой #define предварительной обработкой директива, если только второе определение не является функционально-подобным макроопределением, имеющим одинаковое число и написание параметров, и два списка замены идентичны.

И в разделе 4p2 говорится следующее о нарушениях ограничений:

Если требование '' должен '' или '' не будет '' ', которое появляется вне ограничения или ограничения времени выполнения, поведение не определено. Неопределенное поведение иное обозначено в настоящем международном стандарте словами «неопределенный ehavior '' или отсутствием какого-либо явного определения поведения. Нет разницы в акценте между этими тремя; все они описывают «поведение, которое не определено».

Таким образом, переопределение макроса вызывает неопределенное поведение . Вы должны использовать #undef, если хотите переопределить макрос.

1 голос
/ 10 марта 2020

Вы действительно должны привыкнуть к использованию #undef перед переопределением макроса! Большинство компиляторов генерируют предупреждение; однако, согласно C99 Standard (а также C18 Standard - параграфы одинаковы в обоих):

6.10.3 Замена макроса ... 2 Идентификатор, определенный в настоящее время как объектоподобный макрос, не должен быть переопределен другой директивой предварительной обработки #define, если второе определение не является объектно-подобным определением макроса и два списка замены не идентичны. Аналогично, идентификатор, в настоящее время определяемый как функционально-подобный макрос, не должен быть переопределен другой директивой предварительной обработки #define, если только второе определение не является функционально-подобным определением макроса, которое имеет одинаковое число и написание параметров, а два списка замены идентичны .

'Списки замещения' для макроса LEN_OSG (подобного объекту) в вашем примере 59, а затем 70 - которые не идентичны.

...