Ошибка препроцессора C

Я ожидал, что код выведет suse.sys, но на самом деле он выводит win.sys. Почему это так?

 #define SYS SUSE

 #if SYS == WIN
   #define HDR "win.sys"
 #elif SYS == SUSE
   #define HDR "suse.sys"
 #else
   #define HDR "default.sys"
 #endif
 #include HDR
 #include <stdio.h>

 int main()
 {
   char *name = HDR;
   printf("%s\n", name);
   return 0;
 }

Это похоже на пример во втором издании языка программирования C. Файлы .sys ничего не содержат, они бесполезны.


person CS Student    schedule 09.07.2014    source источник
comment
Определены ли HDR и SUSE?   -  person unwind    schedule 09.07.2014
comment
HDR определяется в операторе if, а SUSE не определяется. SUSE — это просто текст замены токена SYS.   -  person CS Student    schedule 09.07.2014
comment
Что именно выдает, когда вы пытаетесь скомпилировать это? SUSE может вообще не быть определено... также: char *name должно быть const char *name (придирка)   -  person Elias Van Ootegem    schedule 09.07.2014
comment
@EliasVanOotegem Результатом является win.sys, и спасибо за совет по использованию const.   -  person CS Student    schedule 09.07.2014
comment
@CSStudent Да, я имел в виду WIN, а не HDR, конечно.   -  person unwind    schedule 09.07.2014
comment
Возможно ли, что как-то WIN == SUSE ?   -  person n0p    schedule 09.07.2014
comment
@CSStudent: попробуйте распечатать все макросы, SYS, WIN и SUSE, посмотрите, не совпадает ли значение WIN со значением SUSE   -  person Elias Van Ootegem    schedule 09.07.2014
comment
Первый #if заменяется на #if SUSE == WIN, SUSE и WIN (я предполагаю) не определены, поэтому по умолчанию они равны 0 (потому что они используются в арифметическом выражении), поэтому он оценивается как #if 0 == 0, что равно 1, поэтому HDR определено до "suse.sys". Кажется, вы хотите сравнить строки препроцессором, что невозможно.   -  person mafso    schedule 09.07.2014
comment
@unwind Это может быть моя проблема. WIN вообще не определяется. Я просто думал, что if проверяет SYS (SUSE) на строку после ==. Действительно ли if проверяет наличие #define с этим именем? (а затем значение, связанное с именем #define).   -  person CS Student    schedule 09.07.2014
comment
@mafso Да, это объясняет. Я не думал об этом, сравнивая два значения имен #define. Спасибо.   -  person CS Student    schedule 09.07.2014
comment
@CSStudent См. комментарий mafso, который в значительной степени прибил его.   -  person unwind    schedule 09.07.2014
comment
@CSStudent, как указал mafso: сравнение строк невозможно   -  person Elias Van Ootegem    schedule 09.07.2014
comment
Таким образом, вы можете добавить еще два определения: #define WIN 0 и #define SUSE 1 или что-то в этом роде.   -  person Ben    schedule 09.07.2014


Ответы (1)


Сравнение препроцессора с == работает с целочисленными значениями, а не со строками или именами макросов. Вы должны быть в состоянии исправить это, сначала определив макросы SUSE и WIN с целочисленными значениями, например,

#define SUSE 1
#define WIN 2
#define SYS SUSE

После этого как SYS, так и SUSE разрешаются в целое число 1, и сравнение должно работать.

Однако я бы предложил более традиционный подход к определению разных макросов для систем, например:

#define SYS_SUSE
//#define SYS_WIN

#if defined(SYS_SUSE)
#define HDR "suse.sys"
#elif defined(SYS_WIN)
#define HDR "win.sys"
#else
#define HDR "default.sys"
#endif

Преимущество этого подхода в том, что он позволяет более удобно указывать систему в командной строке, make-файлах и т. д., не завися от числовых констант, определяемых в каждом контексте:

cc -DSYS_WIN -c foo.c
person Arkku    schedule 09.07.2014
comment
+1 за то, что дал оба решения, близкое к тому, как его пробовал OP, и лучший подход к тому же (включая рассуждение, почему оно лучше). - person mafso; 10.07.2014