当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
示例代码:
struct S { int x; };
int func()
{
S s{2};
return (int &)s; // Equivalent to *reinterpret_cast<int *>(&s)
}
Run Code Online (Sandbox Code Playgroud)
我认为这很常见,被认为是可以接受的.该标准确保结构中没有初始填充.但是,这种情况未在严格别名规则(C++ 17 [basic.lval]/11)中列出:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
- (11.1)对象的动态类型,
- (11.2)对象的动态类型的cv限定版本,
- (11.3)与对象的动态类型类似(如7.5中所定义)的类型,
- (11.4)与对象的动态类型对应的有符号或无符号类型的类型,
- (11.5)一种类型,它是有符号或无符号类型,对应于对象动态类型的cv限定版本,
- (11.6)聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),
- (11.7)一种类型,它是对象的动态类型的(可能是cv限定的)基类类型,
- (11.8)char,unsigned char或std :: byte类型.
很明显,对象s
正在访问其存储值.
项目符号点中列出的类型是执行访问的glvalue的类型,而不是被访问对象的类型.在这段代码中,glvalue类型int
不是聚合类型或联合类型,排除了11.6.
我的问题是:这个代码是否正确,如果是,那么允许上述哪一个要点?
放置new的返回值与其操作数的转换值之间是否存在(语义)差异?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
Run Code Online (Sandbox Code Playgroud)
是否a
和b
以某种方式有什么不同?
编辑:根据DaBler的评论,这个问题告诉我,如果使用const/reference成员则存在差异:使用const成员放置新类和赋值
所以,我的小位的更新问题:是否a
和b
以任何方式不同,如果Foo
没有const或引用成员?
c++ strict-aliasing placement-new language-lawyer reinterpret-cast
C++ 17(expr.add/4)说:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式P指向具有n个元素的数组对象x的元素x [i],则表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x [i + j]如果0≤i+j≤n; 否则,行为未定义.同样地,如果0≤i-j≤n,则表达式P-J指向(可能是假设的)元素x [i-j]; 否则,行为未定义.
struct Foo {
float x, y, z;
};
Foo f;
char *p = reinterpret_cast<char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
Run Code Online (Sandbox Code Playgroud)
该行标有(*)UB?reinterpret_cast<char*>(&f)
不指向char数组,而是指向浮点数,因此根据引用的段落它应该是UB.但是,如果它是UB,那么它offsetof
的用处将是有限的.
是UB吗?如果没有,为什么不呢?
我正试图称这种方法
#define SIZE 16
void DoSomething(char(&value)[SIZE])
{
}
Run Code Online (Sandbox Code Playgroud)
从这个方法:
void BeforeDoingSomething(char* value, int len)
{
if (len == SIZE)
{
DoSomething(value);
}
}
Run Code Online (Sandbox Code Playgroud)
试图这样做会给我这个错误:
不能使用"char*"类型的值初始化类型为"char(&)[16]"(非const限定)的引用
有关如何让编译器接受value
函数传递的任何提示BeforeDoingSomething
?