【问题标题】:memcpy to string buffer defined in macromemcpy 到宏中定义的字符串缓冲区
【发布时间】:2017-06-06 13:15:29
【问题描述】:

我正在使用 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 的作用是常量,不能修改。

【问题讨论】:

  • 宏是一个红鲱鱼 - 它们只是代码复制和粘贴。替换宏后,生成的代码是否有意义?
  • 原因"VERY LONG" 失败可能是因为它溢出了为"ABC" 分配的内存块。
  • @SkyLeeCorp 这说明了您所在公司的稳定性。老同事和新同事都不认识 C.:)
  • 是的,当我将宏更改为像“Z”这样的真实字符串时,它也可以工作。
  • “某位老同事写的代码”——我真诚的建议是:“为你的生命奔跑吧!”

标签: c string macros memcpy


【解决方案1】:

在您的代码中

  memcpy(SOMEDATA, "OK", sizeof("OK"));

相同
  memcpy("ABC", "OK", sizeof("OK"));

是尝试修改字符串文字的一种非常不寻常的方式。它导致undefined behavior。与其他情况相同,正如我们所知,UB 的结果是,嗯,任何东西。

也就是说,

   printf(SOMEDATA);

可能是有效但不好的做法,如果不需要转换,使用puts()fputs() 更安全。

最后,

我以前认为 MACRO 的作用是常量,不能修改。

好吧,您可能对#define 语句感兴趣。 #define 语句是在编译时发生的文本替换。如果将文字(或常量)值用作定义语句,是的,它不能更改(遵循常量或文字的属性)但是如果定义语句定义了变量名称,那么该变量,如果一个可修改的左值,肯定是可以修改的。

TL;DR #define 语句是文本替换,它们的更改取决于替换列表中的元素。

【讨论】:

  • 感谢您的解释,它有很大帮助!但我宁愿编译器提出一些抱怨。
  • @SkyLeeCorp 很好,你可以使用-Wwrite-strings 和 gcc 来获得 一些 提示。试试看。
【解决方案2】:

C 标准(6.4.5 字符串文字)中的这句话对你很有用

7 不确定这些数组是否是不同的,前提是它们的 元素具有适当的值。如果程序试图 修改这样的数组,行为未定义。

引用的第一句话说两个具有相同值的字符串文字可以作为不同的数组或同一个数组存储在静态内存中,

所以其实这个表达式在if语句的条件中

#define SOMEDATA    "ABC"

//...

if ( SOMEDATA == SOMEDATA )
{
    //...
}

根据编译器的选项设置可以产生真或假。

也就是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 标准。

【讨论】:

    猜你喜欢
    • 2022-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多