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

C中的严格混叠规则和类型混叠

龚睿
2023-03-14

当违反严格的混淆现象规则时,我试图掌握未定义的行为。为了理解它,我读了很多关于SO的文章。然而,还有一个问题:我并不真正理解两种类型的非法别名。cpp-参考指出:

类型混淆现象

每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型对象的存储值时,除非以下之一为真,否则行为未定义:

  • AliasedType和DynamicType类似
  • AliasedType是DynamicType的有符号或无符号变体(可能是cv限定的)
  • AliasedType是std::byte、(自C 17以来)char或unsigned char:这允许检查任何对象的对象表示形式,作为字节数组

我还在SO上找到了一个很好的例子,我清楚地看到了这个问题:

int foo( float *f, int *i ) { 
    *i = 1;               
    *f = 0.f;            

   return *i;
}

int main() {
    int x = 0;

    std::cout << x << "\n";   // Expect 0
    x = foo(reinterpret_cast<float*>(&x), &x);
    std::cout << x << "\n";   // Expect 0?
}

< code>int和< code>float是不相似的类型,这个程序可能会造成严重破坏。我没有看到和理解的是下面的修改:

struct A
{
    int a;
};

struct B
{
    int b;
};

A foo( A *a, B *b ) { 
    a->a = 1;               
    b->b = 0;            

    return *a;
}

int main() {
    A a;
    a.a = 0;


    std::cout << a.a << "\n";   // Expect 0
    a = foo(&a, reinterpret_cast<B*>(&a));
    std::cout << a.a << "\n";   // Expect 0?
}

< code>A和< code>B是相似的类型并且一切正常吗,或者它们是非法的别名并且我有未定义的行为。如果它是合法的,这是因为< code>A和< code>B是集合吗(如果是,我需要做些什么来使它成为未定义的行为)?

任何提醒和帮助将不胜感激。

编辑 关于重复的问题

我知道这篇文章,但我看不出他们在哪里澄清了哪些类型是相似的。至少没有达到我能理解的程度。因此,如果你不结束这个问题,那就太好了。

共有3个答案

赫连心思
2023-03-14
匿名用户

关于类似类型,<code>reinterpret_cast</code>部分有一些有用的解释和示例:

非正式地,两种类型是相似的if,忽略了顶级cv资格:

    < li >它们是同一类型;或者 < li >它们都是指针,指向的类型相似;或者 < li >它们都是指向同一个类的成员的指针,并且被指向的成员的类型是相似的;或者 < li >它们都是相同大小的数组或者都是未知界限的数组,并且数组元素类型相似。

例如:

    < Li > < code > const int * volatile * 和< code>int * * const类似; < Li > < code > const int(* volatile S::* const)[20]与< code > int(* const S::* volatile)[20]类似; < Li > < code > int(* const *)(int *)和< code > int(* volatile *)(int *)类似; < Li > < code > int(S::*)()const 和< code>int (S::*)()不相似; < li> int (*)(int *)和< code>int (*)(const int *)不相似; < Li > < code > const int(*)(int *)和< code>int (*)(int *)不相似; < Li > < code > int(*)(int * const)和< code>int (*)(int *)相似(它们是同一类型); < li> 标准::对

此规则支持基于类型的别名分析,其中编译器假定通过一种类型的glvalue读取的值不会被写入另一种类型glvalue而修改(根据上述例外情况)。

注意,作为一种非标准的语言扩展,许多C编译器放宽了这一规则,允许通过联合的非活动成员进行错误类型的访问(这种访问在C中不是未定义的

曹昊焱
2023-03-14

在表达式<code>b中-

在[expr.ref]/1中,指定类成员访问构成对对象b的访问(在-的左侧)

后缀表达式,后跟一个点 。或箭头 -

[67]如果对类成员访问表达式进行求值,即使结果不需要确定整个后缀表达式的值,例如id表达式表示静态成员,也会进行子表达式求值。

大胆的挖掘

所以 b-

宦瀚
2023-03-14

不,这是不合法的,你有未定义的行为:

8.2.1价值类别[basic.lval]

11如果程序试图通过以下类型之一以外的glvalue访问html" target="_blank">对象的存储值,则行为未定义:63

(11.1)-对象的动态类型,

(11.2)-对象动态类型的cv限定版本,

(11.3)-类似于(如7.5中定义的)对象的动态类型的类型,

(11.4)-对应于对象动态类型的有符号或无符号类型,

(11.5)-与对象的动态类型的cv限定版本相对应的有符号或无符号类型,

(11.6) — 在其元素或非静态数据成员(递归地包括子聚合或包含的联合的元素或非静态数据成员)中的上述类型之一的聚合或联合类型,

(11.7)-对象动态类型的(可能是cv限定的)基类类型的类型,

(11.8)-字符,无符号字符,或std::byte类型

63)本列表的目的是指定对象可能或可能不存在别名的情况。

 类似资料:
  • 下面的getValue()成员函数是否违反了c严格别名规则? 根据该标准,我认为setValue()违反了严格的混淆现象,因为Double既不是聚合类型,也不是IEEE754_64的基类。 getValue()呢?当数据成员采用位字段形式时,它是否是一种未定义的行为,如下例所示? 我正在一个大型项目中使用类似的代码。GCC-O2和-O3输出错误值。如果我添加-fno严格的别名,问题就不存在了。此外

  • 我已经浏览了一些关于类似主题的查询和一些与之相关的材料。但我的查询主要是为了理解下面代码的警告。我不想要修复!!我知道有两种方法,联合或使用memcpy。 请注意以下要点 1。这里涉及的两种类型都是32位。(还是我错了?) 2。两者都是局部变量。 编译器特定点:<br>1.代码应该与平台无关,这是一个要求 2.我在GCC上编译,它就像预期的那样工作。(我可以将int重新解释为float),这就是为

  • 混合配置的规则项之间的叠加使用是通过数据源名称和表名称关联的。 如果前一个规则是面向数据源聚合的,下一个规则在配置数据源时,则需要使用前一个规则配置的聚合后的逻辑数据源名称; 同理,如果前一个规则是面向表聚合的,下一个规则在配置表时,则需要使用前一个规则配置的聚合后的逻辑表名称。 配置项说明 <beans xmlns="http://www.springframework.org/schema/b

  • 混合配置的规则项之间的叠加使用是通过数据源名称和表名称关联的。 如果前一个规则是面向数据源聚合的,下一个规则在配置数据源时,则需要使用前一个规则配置的聚合后的逻辑数据源名称; 同理,如果前一个规则是面向表聚合的,下一个规则在配置表时,则需要使用前一个规则配置的聚合后的逻辑表名称。 配置项说明 # 数据源配置 # 数据源名称,多数据源以逗号分隔 spring.shardingsphere.datas

  • 混合配置的规则项之间的叠加使用是通过数据源名称和表名称关联的。 如果前一个规则是面向数据源聚合的,下一个规则在配置数据源时,则需要使用前一个规则配置的聚合后的逻辑数据源名称; 同理,如果前一个规则是面向表聚合的,下一个规则在配置表时,则需要使用前一个规则配置的聚合后的逻辑表名称。 配置项说明 dataSources: # 配置真实存在的数据源作为名称 write_ds: # ...省略

  • 混合配置的规则项之间的叠加使用是通过数据源名称和表名称关联的。 如果前一个规则是面向数据源聚合的,下一个规则在配置数据源时,则需要使用前一个规则配置的聚合后的逻辑数据源名称; 同理,如果前一个规则是面向表聚合的,下一个规则在配置表时,则需要使用前一个规则配置的聚合后的逻辑表名称。 配置项说明 /* 数据源配置 */ HikariDataSource writeDataSource0 = new H