我遇到了在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;
}
提前感谢您的帮助,
乙
答案 0 :(得分:2)
问题可能在于宏。 tmp变量是在一个块中定义的,我猜想在重新评估之后,即在输入smemcpy之前,该块立即被保留。这样,变量的地址变得毫无意义。一些优化可以覆盖地址,重新利用内存或在未优化的构建中保持原样。只是一个想法,不能确认。
答案 1 :(得分:2)
get_pointer
的定义使用表达式中的语句,即GCC extension。其语义几乎没有记录,并且没有理由相信在语句表达式中声明的对象的存储持续时间超出了语句的评估范围。
因此,在准备对smemcpy
的调用时,编译器可以通过创建对象get_pointer
来评估tmp
,将其地址生成为statement-expression的值,并销毁对象tmp
。然后,不再存在的对象的现在无效的地址将传递给smemcpy
,后者会复制无效数据,因为用于tmp
的空间已被重新用于其他目的。
使用memcpy
时代码可能有效,因为memcpy
是GCC已知的特殊函数,GCC以各种特殊方式对其进行优化。
复合文字应该有用; C标准指定函数体内的复合文字具有与封闭块关联的自动存储持续时间。如果我们按如下方式定义get_pointer
,则封闭块包含整个smemcpy
调用:
#define get_pointer(value) (& (__typeof__(value)) { value })