【问题标题】:Memcpy on stack memory [duplicate]堆栈内存上的 Memcpy [重复]
【发布时间】:2012-04-12 23:38:51
【问题描述】:

可能重复:
What is the difference between char a[] = “string” and char *p = “string”?

在堆栈内存和堆内存上使用 memcpy 有什么区别? 以下代码适用于 Tru64,但在 LINUX 上会出现段错误

char * string2 = "            ";
(void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));

第二个版本适用于 LINUX

char * string2 = malloc(sizeof(char)*12);
(void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));

有人能解释一下 LINUX 上的段错误吗?

【问题讨论】:

  • 堆栈:不是你想象的那样。
  • 您的强制转换完全是滥用,使代码几乎无法阅读。它们都不是必需的,甚至没有用。 sizeof(char) 也被定义为 1。 malloc 根据char 的大小计算要分配的大小。
  • 顺便说一句,在 Linux 上运行的第二个版本中,string2 指向的字符串不能保证在 memcpy 完成后被 nul 终止。这可能会在以后给您带来一些问题。
  • @Alexander:代码很荒谬——即使实现似乎允许修改字符串文字也是愚蠢的,而且为什么不直接写char *string2 = "ALT=---,--<2 spaces>";?如果应用程序对安全至关重要,那么您需要特别仔细地查看修改该字符串文字对 Tru64 的影响。出现在代码不同部分的相同字符串字面量可以指向相同的内存,因此可能(希望不是)原作者依赖memcpy 在其他地方产生另一个"<12 spaces>" 实例代码突然改了!

标签: c linux memcpy


【解决方案1】:

第一个示例有一个未定义行为。因此它可能正常工作或不正常工作或显示任何随机行为。

说明:
第一个例子,声明了一个指向字符串文字的指针string2。字符串文字存储在实现定义的只读内存位置。不允许用户程序修改此内存。任何这样做的尝试都会导致未定义行为

参考:

C99 标准 6.4.5/5“字符串文字 - 语义”:

在翻译阶段 7 中,将一个字节或零值代码附加到由一个或多个字符串文字产生的每个多字节字符序列。然后使用多字节字符序列来初始化一个静态存储持续时间和长度刚好足以包含该序列的数组。对于字符串字面量,数组元素的类型为 char,并使用多字节字符序列的各个字节进行初始化;对于宽字符串文字,数组元素的类型为 wchar_t,并使用宽字符序列进行初始化...

如果这些数组的元素具有适当的值,则未指定这些数组是否不同。 如果程序尝试修改这样的数组,则行为未定义。

【讨论】:

  • 特别是,字符串" " 曾经存储在堆栈中的假设很可能是错误的。
【解决方案2】:

在第一个示例中,您必须区分指针和实际字符串内容:虽然指针 (string2) 在堆栈上,但实际字符串字节不在。有一个很好的变化是它们在只读的常量区域中,因此是段错误。

【讨论】:

  • +1 用于解决可能的实际混淆来源。
【解决方案3】:

首先,行为是未定义的。从 C99,6.4.5/6:

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

实际上,操作系统选择将关联的图像部分加载到只读内存中;因此,当您尝试写入时会出现段错误。

【讨论】:

    【解决方案4】:

    在第一个示例中,您不在堆栈内存中,而是在.rodata(只读数据)部分。字符串字面量具有静态存储持续时间,不需要修改。

    void foo(void)
    {
        // string array has automatic storage duration
        char string[] = "            ";  
    
        // string2 pointer has automatic storage duration and points to
        // a string literal that a static storage duration
        char *string2 = "            "; // string2 pointer has
    }
    

    【讨论】:

      【解决方案5】:

      在第一种情况下,memcpy 的目标是字符串文字,正如其他人所指出的那样。

      在第二种情况下:不要强制转换。避免使用魔法常数。 Sizeof(char) == 1.

      #include <stdlib.h>
      #include <string.h>
      
      char * string2 = malloc(1+strlen("ALT=---,--"));
      (void)memcpy(string2, "ALT=---,--"), 1+strlen("ALT=---,--") );
      

      ,相当于:

      char * string2 = malloc(1+strlen("ALT=---,--"));
      (void)strcpy(string2, "ALT=---,--") );
      

      顺便说一句:原来,常数 '10' 太小了;终止的 nul 字节不会被复制,字符串将不会终止。

      【讨论】:

        【解决方案6】:

        你可以试试这个: char string2[] = " "; (void)memcpy((char *)string2,(char *)("ALT=---,--"),(size_t)(10));

        【讨论】:

          【解决方案7】:

          将您的第一个示例更改为:

          char string2 [] = "            ";
          (void)memcpy((char *)(string2),(char *)("ALT=---,--"),(size_t)(10));
          

          然后您将比较堆栈内存与堆内存。

          【讨论】:

            猜你喜欢
            • 2011-08-15
            • 2012-09-23
            • 2011-03-29
            • 2020-04-24
            • 2011-02-11
            • 2021-05-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多