我正在使用avrx在自定义微型设备上构建软件,但我仍然是C的新手。 如makefile所示,它使用“c99 plus GCC extensions”。 今天我终于碰到了一位老同事写的一段代码,这让我非常困惑:
#define SOMEDATA "ABC"
void main(void)
{
memcpy(SOMEDATA, "OK", sizeof("OK"));
printf(SOMEDATA);//it works just fine?!?!?
memcpy(SOMEDATA, "VERY_LONG", sizeof("VERY_LONG"));
printf(SOMEDATA);//well, now it go nuts. all i see is some random data.
}
为什么呢?
为什么main()
中的逻辑表现得那样?我以前认为MACRO就像常量一样,无法修改。
答案 0 :(得分:2)
在您的代码中
memcpy(SOMEDATA, "OK", sizeof("OK"));
与
相同 memcpy("ABC", "OK", sizeof("OK"));
是尝试修改字符串文字的非常异常方式。它会导致undefined behavior。与其他情况相同,正如我们所知,UB的结果也是如此。
那就是说,
printf(SOMEDATA);
可能有效,但操作不佳,如果不需要转换,则使用puts()
或fputs()
会更安全。
最后,
我以前认为MACRO就像常量一样,无法修改。
好吧,您可能对#define
语句感兴趣。 #define
语句是文本替换,在编译时发生。在一种情况下,一个文字(或常量)值被用作一个define语句,是的,它不能被改变(遵循常量或文字的属性)但是在一种情况下,一个define语句定义一个变量名,然后该变量,如果一个可修改的左值,可以肯定修改。
TL; DR #define
语句是文本替换,它们的更改取决于替换列表中的元素。
答案 1 :(得分:1)
来自C标准(6.4.5字符串文字)的引用将对您有用
7未指明这些阵列是否与它们不同 元素具有适当的值。如果程序试图 修改这样的数组,行为是未定义的。
引用的第一个陈述说两个具有相同值的字符串文字可以作为不同的数组存储在静态存储器中,也可以作为同一个数组存储,
所以实际上这个表达式在if语句的条件下
#define SOMEDATA "ABC"
//...
if ( SOMEDATA == SOMEDATA )
{
//...
}
可以产生true或false,具体取决于编译器选项的设置。
这就是memcpy
memcpy(SOMEDATA, "OK", sizeof("OK"));
//..
memcpy(SOMEDATA, "VERY_LONG", sizeof("VERY_LONG"));
等同于
memcpy("ABC", "OK", sizeof("OK"));
//..
memcpy("ABC", "VERY_LONG", sizeof("VERY_LONG"));
可以写入相同的内存范围或不同的内存范围。
引用的第二个陈述说任何改变字符串文字的尝试都会导致程序的未定义行为。
考虑到根据C标准,在托管环境中使用的没有参数的函数main应声明为
int main( void )
^^^^
虽然某些编译器作为Microsoft编译器允许使用void类型作为main的返回类型,但最好遵循C标准。