【问题标题】:How to cast a pointer (make it bigger)如何投射指针(使其更大)
【发布时间】:2012-03-27 07:46:28
【问题描述】:

我的程序/进程异常退出?我怀疑以下代码有问题:

有两个typedef TYPE1,TYPE2。 (TYPE1的尺寸比TYPE2大)

TYPE1 var1;
TYPE2 var2;
....
....var2 has been assigned.
....
memset(&var1, 0, sizeof(var1));
memcpy(&var1, (TYPE1 *)&var2, sizeof(TYPE1));
printf("....");
  1. Cast var2 可能会导致访问非法内存从而导致分段错误?我认为它可能会弄乱内存中 var2 之后的数据,但不能造成分段错误?我在这里找到了我的程序退出,因为下面的 printf() 没有打印任何东西。

  2. Cast 会破坏内存中 var2 之后的数据,即使它只是被读取(var2 只是 memcpy() 的来源。

  3. 如果我像 memcpy(&var1, (TYPE1 *)&var2, sizeof(TYPE2));

  4. 这样更改它会发生什么

谢谢。

【问题讨论】:

  • printf 的输出通常被缓冲。在崩溃之前,您的代码可能已经超过了printf。您可能想要使用调试器或至少在此处发布更多代码。
  • 你不需要演员表。 C 语言中的强制转换几乎总是错误的,并且表明需要重构。除此之外,在memcpy() 调用中,您试图在对象结束后通过&var2 访问数据(sizeof var1 > sizeof var2)。
  • @pmg - 我可以限定“C 中的强制转换几乎总是错误的”吗? “将指针转换为 void 指针几乎总是错误的,因为它从来没有必要”(说实话,在将任何指针分配给 void * 需要在现代 C 中进行转换时,我想不出任何情况。所以也许我正在wish-washy),我不希望人们认为“...(unsigned int)c”或“foo((double)i”属于同一类错误。
  • @gbulmer:在我的脑海中,唯一需要强制转换的地方是在将参数传递给可变参数函数以及使用<ctype.h> 中声明的函数时。大多数其他类型转换可以通过编译器的隐式转换更好地完成。

标签: c


【解决方案1】:

首先:在使用memcpy 时,您不需要将&var2 转换为TYPE1*。 memcpy 期望 void*,并且任何指针类型都可以转换为 void*。

这里的问题是,当TYPE1 大于TYPE2 并且您使用sizeof(TYPE1) 作为大小将数据从var2 复制到var1 时,memcpy 最终会从超出的内存中读取var2。结果,您正在访问不允许访问的内存。因此,分段错误是您可能遇到的最好的情况,因为该错误也可能在很长一段时间内都被忽视,直到它真正引起麻烦(未定义的行为是这里的关键短语)。

当您仅将sizeof(TYPE2) 字节从var2 复制到var1 时,就内存访问而言,您是可以的(只要TYPE1 确实大于TYPE2)。

【讨论】:

    【解决方案2】:

    I.它可能导致分段错误,但不是因为您已转换为(TYPE1*),而是因为您正在从var2读取sizeof(TYPE1)。另外它在var2 之后不会弄乱数据。事实上,您无需担心数据损坏。 Segmentation fault 的真正目的是防止这种非法的内存访问,无论是读取还是写入

    II. 不会破坏 var2 之后的数据。 memcpy的原型是

    `void * memcpy ( void * destination, const void * source, size_t num );`
    

    注意const。所以它保证source 数据不会被修改。强制转换也无法决定它是否是无效的内存访问。您尝试复制的字节数、源大小和目标大小都很重要。

    III. 正如其他人指出的那样,强制转换无关紧要,在这种情况下,由于您要从较小的数据结构复制到较大的数据结构,因此不会出现分段错误。

    【讨论】:

    • 你的意思是会导致分段错误但不会弄乱数据是seg-fault更可取吗? :) 在传递给 memcpy 时作为旁注转换无济于事,因为参数始终为 void*
    • @keety OP 似乎担心数据损坏,这就是为什么我提到它不会发生这样的事情。无论如何,我编辑了我的答案以使我的意图更清晰
    • I: 是否保证分段错误?或者它是未定义的行为?您的回答似乎自信地表明分段错误是唯一不正确的可能结果。
    【解决方案3】:

    我认为这里遗漏了重要的一点。

    不要让指针变大或变短。无论是 int、char、float 的所有指针都具有相同的大小,并且只包含一个地址(过去唯一的例外是我们在 16 位 DOS 时代的 c 中有近或远指针)。指针的静止大小与机器上的整数大小相同。

    所以问题标题具有误导性。但是你会问为什么我们需要带有指针的类型呢?

    当我们将一个指针从 TYPE_1 * 转换为 TYPE_2 * 时,我们基本上是在告诉该指针将引用什么类型的变量,以及当我们编写实例时它会跳过多少字节

    int * a;
    a++; // skips four bytes if it is a 32 bit integer/machine
    
    double *b;
    b++; // skips 8 bytes
    

    【讨论】:

      猜你喜欢
      • 2014-09-05
      • 1970-01-01
      • 2014-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      相关资源
      最近更新 更多