当前位置: 首页 > 知识库问答 >
问题:

关于char的泛型指针和严格混淆现象

丌官嘉勋
2023-03-14

我不知道为什么下面的代码运行得很好,没有< 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 兼容的类型,要么是限定版本,要么是有符号类型,要么是无符号类型,要么是字符类型。

那么,为什么允许这样做?

共有1个答案

郜彬
2023-03-14

这是不允许的。您发布的标准部分显示了允许哪些类型为对象添加别名。

代码被编译的事实并不意味着它是正确的。您的代码有三个问题,使得程序表现出未定义的行为。

首先,将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?英特尔规范中的两个“代码操作”也不同,一个从左边计数或索引,另一个从右边计数或索引。 也许有人能对此有所了解,我没