2011-02-01 4 views
4
#include <stdio.h> 
#define print_int(a) printf("%s : %d\n",#a,(a)) 
int main(void) { 
    int y = 10; 
    print_int(y); 
    return 0; 
} 

Я занимаюсь классом и попросили объяснить, почему это плохо ... Поэтому я думаю, что строкой #a является проблема. Он работает, так почему это опасно?stringizing #a in define, почему это плохо

+4

Тот, кто дал вам это задание, пытается наложить на учащихся баритоновую точку зрения. Нет основанной причины, что это должно считаться плохим. –

+0

Я пытаюсь понять, почему это должно быть плохо, прежде чем иметь мнение о политической стороне этого ... я, вероятно, буду так кодироваться – user501743

+0

Я даже не уверен, почему кто-то сочтет это плохим. Я никогда не слышал, чтобы это цитировалось как практика, «считающаяся вредной» до ... –

ответ

3

, потому что он обходит тип безопасности. Что происходит, когда кто-то ненавидит вас и идет print_int("5412");

#include <stdio.h> 
#define print_int(a) printf("%s : %d\n",#a,(a)) 
int main(void) { 
    print_int("1123123"); 
    return 0; 
} 

выходов

$ gcc test.c 
test.c: In function ‘main’: 
test.c:4: warning: format ‘%d’ expects type ‘int’, but argument 3 has type ‘char *’ 
$ ./a.out 
"1123123" : 3870 
+0

C99 для победы: '#define print_int (a) printf ("% s:% d \ n ", # a, (int) { a}) ' – Christoph

+1

@Enabren: предупреждение в вашем ответе является любезностью компилятора, тогда как одно из моего кода является фактическим нарушением семантики языка C (см. C99 6.5.4 § 3) и, вероятно, должно быть ошибкой, если 'std = c99' установлен ... – Christoph

+0

Я не верю, что' (int) {a} 'является допустимым составным литералом, но я могу ошибаться. Конечно, это будет: '(int [1]) {a} [0]'. –

1

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

int a = 15; 
print_int(a++); 
+3

вообще, может быть, но не в этом случае ... – Christoph

+1

Действительно? Почему предпроцессорное зло? Это/может быть сложным (но мощным), но это не зло. – hlovdal

+0

Хм, я думаю, что «зло», вероятно, недостаточно акадмическое, объяснение для uni. Я на самом деле никогда не сталкивался с кодом, который использует это в реальной жизни ... – user501743

2

Я не думаю, что это вообще плохо. Оператор stringtize очень полезен для написания макросов, таких как утверждения:

#define assert(x) do { if (!(x)) { printf("assert failed: %s\n", #x); } } while (0) 

Вы злоупотребляете любой полезной функцией. Я когда-то была прекрасная идея «упрощать» Qt Атомы написав:

#define ATOM(x) (((#x)[0] << 24) | ((#x)[1] << 16) | ... 

Таким образом, можно сказать ATOM(MPEG) и получить ('M' << 24 | 'P' << 16 | ...). Фактически, он работал достаточно хорошо, чтобы gcc мог вывести из него целые константы ... Иногда ... Теперь это было зло!

+0

Преобразование из символов в int зависит от контенту, вы должны инкапсулировать это в другой макрос, например. '#define FOUR_CHAR_TO_INT (a, b, c, d) ((a) << 24 | (b) << 16 | ...) 'и' #define ATOM (x) FOUR_CHAR_TO_INT ((# x) [0], (#x) [1], (#x) [2], (#x) [3]) '. – hlovdal

+0

Замечательный способ сделать вашу программу не переносной: используйте поддельные целочисленные константные выражения, которые gcc рассматривает, как если бы они были действительными целочисленными константными выражениями. –

+2

@hlovdal: В коде Бена нет никакой зависимости от эндианта. –

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