【发布时间】:2015-10-04 20:39:30
【问题描述】:
到目前为止,我为这个问题得到的答案有两种完全相反的答案:“它是安全的”和“它是未定义的行为”。我决定重写整个问题,以获得更好的澄清答案,对我和任何可能通过谷歌到达这里的人来说。
另外,我删除了 C 标签,现在这个问题是 C++ 特定的
我正在创建一个 8 字节对齐的内存堆,将在我的虚拟机中使用。我能想到的最明显的方法是分配std::uint64_t 的数组。
std::unique_ptr<std::uint64_t[]> block(new std::uint64_t[100]);
假设sizeof(float) == 4 和sizeof(double) == 8。我想在block 中存储一个浮点数和一个双精度数并打印值。
float* pf = reinterpret_cast<float*>(&block[0]);
double* pd = reinterpret_cast<double*>(&block[1]);
*pf = 1.1;
*pd = 2.2;
std::cout << *pf << std::endl;
std::cout << *pd << std::endl;
我还想存储一个 C 字符串说“你好”。
char* pc = reinterpret_cast<char*>(&block[2]);
std::strcpy(pc, "hello\n");
std::cout << pc;
现在我想存储“Hello, world!”超过 8 个字节,但我仍然可以使用 2 个连续的单元格。
char* pc2 = reinterpret_cast<char*>(&block[3]);
std::strcpy(pc2, "Hello, world\n");
std::cout << pc2;
对于整数,我不需要reinterpret_cast。
block[5] = 1;
std::cout << block[5] << std::endl;
我将block 分配为std::uint64_t 的数组,仅用于内存对齐。我也不希望任何大于 8 字节的内容存储在其中。如果保证起始地址为 8 字节对齐,则块的类型可以是任何类型。
有些人已经回答说我正在做的是完全安全的,但有些人说我肯定是在调用未定义的行为。
我是否编写了正确的代码来实现我的意图?如果不是,什么是合适的方式?
【问题讨论】:
-
任何对指针类型不兼容的对象的访问都违反了别名规则。
-
@xiver77 如果你想要动态内存,那么使用 malloc。它将在堆上分配并分配存储持续时间。 C 有特殊的规则来帮助处理几乎完美地适用于您的案例的别名。
-
为了规避这一切,只需使用 char* 作为堆的“普通”类型并将索引移动 3 位...
-
@FelixPalmen 这表明您显然不了解标准。 C 允许 char 为任何类型起别名,但反之则不行。
-
别名是关于读取和写入,而不是关于声明,任何声明都可以,只要它实际上不用于内存访问——如果你在这一点上停止与你“讨论”仍然坚持你的愚蠢想法。
标签: c++ memory-management