关于C语言预处理器字符串声明的报错问题咨询
先看你的代码:
#include <stdio.h> #define string char* int main(void) { string a[] = { "I", "like", "to", "fight," }, b[] = {"pinch,","and","bite."}; printf("%s %s %s %s %s %s %s\n", a[0], a[1], a[2], a[3], b[0], b[1], b[2]); return 0; }
运行时出现的报错:
exit status 1
main.c: In function 'main':
main.c:7:18: error: excess elements in char array initializer
b[] = {"pinch,","and","bite."};
报错原因
问题出在你定义的#define string char*这个宏上。宏替换是纯文本替换,完全不考虑C语言的声明语法优先级。
当编译器处理string a[] = { ... }, b[] = { ... };这一行时,会把string直接替换成char*,展开后变成:
char* a[] = { "I", "like", "to", "fight," }, b[] = {"pinch,","and","bite."};
在C语言的声明规则里,char* a[], b[]等价于char *a[], b[]——这里的*是绑定到变量a的,不是绑定到类型的。也就是说:
a是指向char的指针数组(char*[]),这和你预期的一致,所以初始化没问题;- 但
b是char类型的数组(char[]),而不是你想要的指针数组!
char类型的数组只能用单个字符串字面量(或者一组字符)初始化,你给它塞了3个字符串字面量,编译器自然会报错“char数组初始化时元素过多”。
解决方法
有两种靠谱的解决方式:
方法1:用typedef代替#define定义类型别名
宏定义不适合用来创建类型别名,改用typedef可以正确处理类型绑定:
#include <stdio.h> typedef char* string; // 这里用typedef代替#define int main(void) { string a[] = { "I", "like", "to", "fight," }, b[] = {"pinch,","and","bite."}; printf("%s %s %s %s %s %s %s\n", a[0], a[1], a[2], a[3], b[0], b[1], b[2]); return 0; }
typedef会真正创建一个类型别名string,代表char*,所以string a[], b[]会被正确解析为两个char*[]类型的数组,初始化就没问题了。
方法2:显式给b加上*
如果你一定要用宏(不推荐),可以在声明b的时候显式加上*,确保它是指针数组:
#include <stdio.h> #define string char* int main(void) { string a[] = { "I", "like", "to", "fight," }, *b[] = {"pinch,","and","bite."}; printf("%s %s %s %s %s %s %s\n", a[0], a[1], a[2], a[3], b[0], b[1], b[2]); return 0; }
但这种方式容易出错,还是优先用typedef更稳妥。
另外补充一点:字符串字面量在C中是const char*类型,所以更规范的写法是把string定义为const char*,避免潜在的未定义行为——不过这是额外的优化,解决当前报错的核心还是上面的两种方法。
内容的提问来源于stack exchange,提问作者DFT95

