我在几个旧的项目中看到过这样的代码: class Class { static void Method() {} }; ((Class*)0)->Method(); 此代码包含未定义的行为,因为它包含解引用空指针(不pipe之后会发生什么)。 这真的没有任何意义 – 在那里将types名称提供给编译器,而编写上面代码的人可以写下这个代码: Class::Method(); 后者会好的。 为什么会有人写前代码? 这是一个很好的旧时代的成语吗?
使用%p转换说明符打印空指针是未定义的行为吗? #include <stdio.h> int main(void) { void *p = NULL; printf("%p", p); return 0; } 这个问题适用于C标准,而不适用于C实现。
我惊讶地意外地发现以下的作品: #include <iostream> int main(int argc, char** argv) { struct Foo { Foo(Foo& bar) { std::cout << &bar << std::endl; } }; Foo foo(foo); // I can't believe this works… std::cout << &foo << std::endl; // but it does… } 我将构造对象的地址传递给它自己的构造函数。 这看起来像来源层面的循环定义。 标准是否真的允许你在对象构造之前将一个对象传入一个函数,或者这个未定义的行为? 我想这并不奇怪,因为所有的类成员函数都有一个指向其类实例的数据的指针,作为一个隐式参数。 数据成员的布局在编译时是固定的。 请注意,我不是问这是否有用或好主意, 我只是在学习更多的课程。
我很好奇初始化列表和序列点。 我刚才读到,初始化列表中的评估顺序是左alignment的。 如果那样的话,评价点之间肯定有某种顺序点,我错了吗? 所以说这是以下有效的代码? 有没有什么会导致未定义的行为? int i = 0; struct S { S(…) {} operator int() { return i; } }; int main() { i = S{++i, ++i}; } 任何和所有的回应表示赞赏。
我正在研究核心常量expression式*中允许的内容, C ++标准草案第5.19节的常量expression式中包含了以下内容: 一个条件expression式是一个核心常量expression式,除非它涉及以下之一作为一个潜在的评估子expression式(3.2),但是没有被评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子expression式不考虑[注意:重载操作符调用一个函数。 并列出了下面的子弹中的排除项(包括我的重点 ): – 注意:例如,包括有符号整数溢出(第5章),某些指针算术(5.7),除以零(5.6)或某些移位操作(5.8) – 结束注释]。 呃 ? 为什么常量expression式需要这个子句来覆盖未定义的行为 ? 常量expression式有什么特别之处,需要不确定的行为才能排除在特殊情况之外呢? 这个条款有没有给我们带来任何好处或工具? 作为参考,这看起来像广义常量expression式的最后一个版本。
如在初始化中涉及左值到右值的转换? 是int x = x; UB? C ++标准在第3.3.2节的声明中有一个令人惊讶的例子,其中一个int用它自己的不确定值进行初始化: int x = 12; { int x = x; } 这里第二个x是用自己的(不确定的)值初始化的。 – 结束示例 ] 哪个Johannes回答这个问题表明是未定义的行为,因为它需要一个左值到右值的转换。 在最新的C ++ 14草案标准N3936可以在这里find这个例子已经改为: unsigned char x = 12; { unsigned char x = x; } 这里第二个x是用自己的(不确定的)值初始化的。 – 结束示例 ] 在C ++ 14中,在不确定的值和未定义的行为方面有什么改变,导致了这个例子的改变?