当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
如果我得到一个bool变量并将其第二位设置为1,则变量同时评估为true和false。使用带有-g选项(gcc-v6.3.0/Linux/RHEL6.0-2016-x86_64/bin/g++ -g main.cpp -o mytest_d)的gcc6.3编译以下代码,然后运行可执行文件。您得到以下内容。
T如何同时等于真和假?
value bits
----- ----
T: 1 0001
after bit change
T: 3 0011
T is true
T is false
Run Code Online (Sandbox Code Playgroud)
当您使用不同的语言(例如fortran)调用函数时,可能会发生这种情况,其中对和错的定义与C ++不同。对于fortran,如果任何位都不为0,则该值为true;如果所有位为零,则该值为false。
#include <iostream>
#include <bitset>
using namespace std;
void set_bits_to_1(void* val){
char *x = static_cast<char *>(val);
for (int i = 0; i<2; i++ ){
*x |= (1UL << i);
}
}
int main(int argc,char *argv[])
{
bool T = 3;
cout <<" value bits " <<endl;
cout <<" …Run Code Online (Sandbox Code Playgroud) 在c ++标准中,在[basic.lval] /11.6中说:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:[...]
- 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括递归地,子聚合或包含联合的元素或非静态数据成员),[...]
这句话是严格别名规则的一部分.
它是否允许我们通过类成员访问进行别名?
class A{ //"casted to" aggregate
int i;
float g;
};
int j=10;
int l = reinterpret_cast<A*>(&j)->i;
Run Code Online (Sandbox Code Playgroud)
根据标准,只有在对象受到左值到右值转换 [conv.lval]/2的情况下才能访问对象值.
[expr.ref]没有规定object-expression必须引用该类型的对象,只是glvalue必须具有类类型(object-expression是点"."左侧的表达式).然而,有一句话反复出现在与成员访问相关的句子中,这可能意味着对我忽略的程序的限制.例如[expr.ref] /4.1:
如果E2是静态数据成员且E2的类型是T,则E1.E2是左值; 表达式指定类的命名成员.
"指定"是否意味着该成员在其生命周期内并且我不能使用类成员访问来进行伪造别名?或者[basic.lval] /11.6允许它?