我不知道为什么下面的代码运行得很好,没有< code>gcc错误(< code >-f strict-aliasing-Wstrict-aliasing = 1 )。
#include <stdio.h>
int
main(void)
{
char n = 42;
char *p = &n;
int *q = (int *)p;
*q = 10;
printf("%d|%d\n", *p, *q);
return 0;
}
如果我遵循严格的别名规则:
n1570,§6.5表达式
对象的存储值只能由具有以下类型之一的左值表达式访问:
-与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
-与对象的有效类型对应的有符号或无符号类型的类型,
-对应于对象有效类型的限定版本的有符号或无符号类型的类型,
-在其成员中包括上述类型之一的聚合或并集类型(递归地包括子聚合或包含并集的成员),或
-字符类型。
但是 *q
没有与 *p
兼容的类型,要么是限定版本,要么是有符号类型,要么是无符号类型,要么是字符类型。
那么,为什么允许这样做?
这是不允许的。您发布的标准部分显示了允许哪些类型为对象添加别名。
代码被编译的事实并不意味着它是正确的。您的代码有三个问题,使得程序表现出未定义的行为。
首先,将char指针分配给int指针。标准不强制它们的对齐和表示,因此结果指针无效。
int *q = (int *)p;
然后,您将charn
对象解释为一个整数,违反了严格的别名。(注意问题中引用的标准)。
*q;
最后,您将int
写入char对象(char n
)的内存中,这会导致溢出,因为int
的大小始终大于char
的大小。
*q = 10;
这是一个典型的严格混叠违规示例: 但假设我们添加第二: 这段代码正确吗(不调用未定义的行为)? 标准[expr.reinterpret.cast]如下: 注意:将“指针到<code>T1</code>”类型的prvalue转换为“指针到 和<code>T2是对象类型,并且<code>T2的对齐要求不比<code>T 1 我们使用 类型的原始指针值来访问 类型。 当优化打开时,GCC和Clang都会
让我们考虑以下(简化)代码来读取二进制文件的内容: 在我看来,下面一行: 包含未定义的行为:我们正在读取类型的成员,它覆盖在对象的数组之上,并且编译器可以自由地假设对象不别名。 问题是:我的解释正确吗?如果是,可以做什么来修复此代码?如果没有,为什么这里没有UB? 注1:我理解严格别名规则的目的(允许编译器避免不必要的内存加载)。此外,我知道在这种情况下,使用<code>std::memcpy</
C(和C)严格的别名规则包括< code>char*和< code>unsigned char*可以为任何其他指针起别名。 AFAIK对于没有类似的规则。 因此,我的问题是:<code>std::byte</code>指针的别名规则是什么? C参考目前仅指定: 与字符类型(char、unsigned char、signed char)一样,它可以用于访问由其他对象(对象表示)占用的原始内存,但与这
我已经运行这个程序好几次了,每次最后打印的p和g的值都是一样的。我不太确定为什么会这样——malloc不能在理论上选择内存中的任何位置让p和g指向吗?为什么p 8总是等于g?如果能澄清,将不胜感激。 谢谢
我正在尝试构建一个类模板,它将一堆类型打包在一个适当大的char数组中,并允许将数据作为单个正确键入的引用访问。现在,根据标准,这可能会导致严格的混淆现象,从而导致未定义的行为,因为我们通过与之不兼容的对象访问数据。具体来说,标准规定: 如果程序尝试通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义: 对象的动态类型, 对象的动态类型的cv限定版本, 与对象的动态类型类似(如4.4
我对两个说明都有点困惑。首先,让我们放弃扫描值为0和未定义的/bsr或bitsize/lzcnt结果的特殊情况--这个区别很明显,不是我的问题的一部分。 让我们取二进制值 计数,返回到位0(即lsb)的索引或距离。 如果CPU上没有可用的BMI,如何模拟为?或者在的情况下位0是MSB?英特尔规范中的两个“代码操作”也不同,一个从左边计数或索引,另一个从右边计数或索引。 也许有人能对此有所了解,我没