未使用字符串时,初始化程序元素不是常量错误
我正在做一些关于Doom源代码的实验。我对C不是很熟悉,但我正在放弃它。我想修改的代码看起来是这样的:未使用字符串时,初始化程序元素不是常量错误
{"sndserver", (int *) &sndserver_filename, (int) "sndserver"},
,我试图做到这一点,而不是(以除去在多个地方硬编码相同的位置):
{"sndserver", (int *) &sndserver_filename, (int) sndserver_filename},
但它给我标题中的错误。我试图在同一个位置声明另一个变量sndserver_filename源自那个在那里做转换,但是一旦我尝试在这里使用它,我得到同样的错误。
是否有一个原因,该字符串将转换为一个int,但该变量不会,并且有办法绕过它?
语境:
#ifdef SNDSERV
extern char* sndserver_filename; // value is "./sndserver"
extern int mb_used;
#endif
结构声明和初始化
typedef struct
{
char* name;
int* location;
int defaultvalue;
int scantranslate; // PC scan code hack
int untranslated; // lousy hack
} default_t;
default_t defaults[] =
{
{"mouse_sensitivity",&mouseSensitivity, 5},
{"sfx_volume",&snd_SfxVolume, 8},
{"music_volume",&snd_MusicVolume, 8},
{"show_messages",&showMessages, 1},
#ifdef NORMALUNIX
{"key_right",&key_right, KEY_RIGHTARROW},
{"key_left",&key_left, KEY_LEFTARROW},
{"key_up",&key_up, KEY_UPARROW},
{"key_down",&key_down, KEY_DOWNARROW},
{"key_strafeleft",&key_strafeleft, ','},
{"key_straferight",&key_straferight, '.'},
{"key_fire",&key_fire, KEY_RCTRL},
{"key_use",&key_use, ' '},
{"key_strafe",&key_strafe, KEY_RALT},
{"key_speed",&key_speed, KEY_RSHIFT},
// UNIX hack, to be removed.
#ifdef SNDSERV
{"sndserver", (int *) &sndserver_filename, (int) "sndserver"},
{"mb_used", &mb_used, 2},
#endif
#endif
#ifdef LINUX
{"mousedev", (int*)&mousedev, (int)"/dev/ttyS0"},
{"mousetype", (int*)&mousetype, (int)"microsoft"},
#endif
{"use_mouse",&usemouse, 1},
{"mouseb_fire",&mousebfire,0},
{"mouseb_strafe",&mousebstrafe,1},
{"mouseb_forward",&mousebforward,2},
{"use_joystick",&usejoystick, 0},
{"joyb_fire",&joybfire,0},
{"joyb_strafe",&joybstrafe,1},
{"joyb_use",&joybuse,3},
{"joyb_speed",&joybspeed,2},
{"screenblocks",&screenblocks, 9},
{"detaillevel",&detailLevel, 0},
{"snd_channels",&numChannels, 3},
{"usegamma",&usegamma, 0},
{"chatmacro0", (int *) &chat_macros[0], (int) HUSTR_CHATMACRO0 },
{"chatmacro1", (int *) &chat_macros[1], (int) HUSTR_CHATMACRO1 },
{"chatmacro2", (int *) &chat_macros[2], (int) HUSTR_CHATMACRO2 },
{"chatmacro3", (int *) &chat_macros[3], (int) HUSTR_CHATMACRO3 },
{"chatmacro4", (int *) &chat_macros[4], (int) HUSTR_CHATMACRO4 },
{"chatmacro5", (int *) &chat_macros[5], (int) HUSTR_CHATMACRO5 },
{"chatmacro6", (int *) &chat_macros[6], (int) HUSTR_CHATMACRO6 },
{"chatmacro7", (int *) &chat_macros[7], (int) HUSTR_CHATMACRO7 },
{"chatmacro8", (int *) &chat_macros[8], (int) HUSTR_CHATMACRO8 },
{"chatmacro9", (int *) &chat_macros[9], (int) HUSTR_CHATMACRO9 }
};
让我试着提供一个解释。
您声明
extern char* sndserver_filename;
然后在(当然,链接时确实)是必需的编译时地址的上下文中使用sndserver_filename
。
但编译时不知道sndserver_filename
的值。在程序开始时它是NULL。稍后,您可以分配给它:
sndserver_filename = "aaa";
,并再次分配:
sndserver_filename = "bbb";
这不是编译时初始化有用。
你真正需要的是一个静态分配的数组,而不是一个指针:
extern char sndserver_filename[];
注意的方括号。
这告诉编译器有一个静态分配的字符数组(此时数组的大小不知道)。
在C文件之一,在全球范围内,你需要做这样的事情:
焦炭sndserver_filename [256];
实际分配内存(并指定大小)。
然后你可以使用sndserver_filename静态初始化,您可以通过使用strcpy的设置它的值(真的,strncpy()函数,以确保您不要复制过去的数组的大小):
strcpy(sndserver_filename, "bbb");
注意
sndserver_filename = "aaa";
现在是一个编译时错误。
非常感谢你的解释!我可以说这确实有效,并且复制链接也提供了一些良好的背景。真的很感激它。 – fibpi
你的编译器说什么:初始化元素不是常量表达式。像&sndserver_filename
这样的地址是一个常量表达式(链接器填充符号的值),但是指针变量可以包含任何地址 - 实际值可能取决于程序的流向,所以它不能用来初始化任何东西。
从C11 6.7.9初始化:
4所有在对于具有静态或线程存储期限为常量表达式或字符串文字的对象的初始化表达式。
这是一个约束和编译器需要诊断违反约束。
你必须保持它不变。但使用宏可以工作。 –
这两行看起来不像犹太教。对于特定的体系结构和特定的编译器来说,它可能是90年代的一种可行的方法,但它在现代C和现代高度优化的编译器中很可能是一个问题。但是,如果没有[mcve],很难说出问题是什么。 – Olaf
我会在一些更深的背景下添加,但它是一个很大的代码片段,我知道它也是不被赞同的。 – fibpi