【问题标题】:gcc optimising away compound statementgcc 优化远离复合语句
【发布时间】:2014-01-13 16:18:58
【问题描述】:

我在为 c 中的通用可调整大小向量实现 push_back 运算符时遇到问题。为了通用性,我需要使用 void 指针作为参数,但实际上我想直接给它赋值。

当我用gcc -o t test.c -std=c99 编译下面的代码时,它会按我的预期打印10。 当我将-O1(或更高版本)添加到编译选项时,程序会打印0

我认为问题出在smemcpy 代码中,因为当我用memcpy 替换它时,我不再有这个问题。

简化代码:

#include <stdio.h>
#include <stdlib.h>

#define get_pointer(value) ({ __typeof__(value) tmp = value; &tmp; })

// copy from src to dst byte by byte
void* smemcpy(void* dst, void const * src, size_t len) {
    char * pdst = (char *) dst;
    char const * psrc = (char const *) src;

    while (len--) {
        *pdst++ = *psrc++;
    }

    return (dst);
}


int main() {
    void* container = malloc(sizeof(int));

    // copy a 10 into the container via a temporary pointer
    smemcpy(container, get_pointer(10), sizeof(int));

    printf("%d\n", ((int*)container)[0]);

    return 0;
}

提前感谢您的帮助,

B

【问题讨论】:

  • 您的get_pointer 语句块正在评估临时对象的地址,不是吗?
  • 今天第二个此类问题,两天内第三个。
  • @hwd 如果这是一个临时对象问题,为什么没有-O1 或者当我使用memcpy 时它会起作用?
  • @user1483596:未定义的行为。
  • 我查看了汇编代码。带有 -O1 的 gcc 优化了 tmp = value 分配,但仍将 &tmp 传递给 smemcpy。

标签: c generics gcc vector memcpy


【解决方案1】:

也许问题出在宏上。 tmp 变量是在一个块中定义的,我猜该块在评估后立即离开,即在输入 smemcpy 之前。这样变量的地址就变得毫无意义。该地址可能会被一些重新利用内存的优化覆盖,或者在未优化的构建中保持不变。只是一个想法,无法确认。

【讨论】:

    【解决方案2】:

    get_pointer 的定义在表达式中使用了一个语句,即GCC extension。这种语义几乎没有记录,并且没有理由相信语句表达式中声明的对象的存储持续时间超出语句的评估。

    因此,在准备调用smemcpy 时,编译器可以通过创建对象tmp 来评估get_pointer,将其地址作为语句表达式的值,并销毁对象tmp。然后将不再存在的对象的现在无效地址传递给smemcpy,这会复制无效数据,因为用于tmp 的空间已被重新用于其他目的。

    当使用memcpy 时,代码可能会起作用,因为memcpy 是GCC 已知的一个特殊函数,并且GCC 会以各种特殊方式对其进行优化。

    复合文字应该可以工作; C 标准规定函数体内的复合文字具有与封闭块相关联的自动存储持续时间。如果我们如下定义get_pointer,则封闭块包括整个smemcpy调用:

    #define get_pointer(value) (& (__typeof__(value)) { value })
    

    【讨论】:

      猜你喜欢
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-06
      • 2011-01-14
      相关资源
      最近更新 更多