问题描述
不管代码有多糟糕",并且假设对齐等在编译器/平台上不是问题,这是未定义或损坏的行为吗?
Regardless of how 'bad' the code is, and assuming that alignment etc are not an issue on the compiler/platform, is this undefined or broken behavior?
如果我有这样的结构:-
If I have a struct like this :-
struct data
{
int a, b, c;
};
struct data thing;
将 a
、b
和 c
作为 (&thing.a)[0]
、(&thing.a)[1]
和 (&thing.a)[2]
?
Is it legal to access a
, b
and c
as (&thing.a)[0]
, (&thing.a)[1]
, and (&thing.a)[2]
?
在每种情况下,在我尝试过的每个编译器和平台上,我尝试过的每个设置都有效".我只是担心编译器可能没有意识到 b 和 thing[1] 是同一个东西,并且存储到 'b' 可能会被放在一个寄存器中[1] 从内存中读取错误的值(例如).在每种情况下,我都尝试过它做了正确的事情.(我当然意识到这并不能证明什么)
In every case, on every compiler and platform I tried it on, with every setting I tried it 'worked'. I'm just worried that the compiler might not realize that b and thing[1] are the same thing and stores to 'b' might be put in a register and thing[1] reads the wrong value from memory (for example). In every case I tried it did the right thing though. (I realize of course that doesn't prove much)
这不是我的代码;这是我必须使用的代码,我对这是坏代码还是损坏代码很感兴趣,因为不同的代码会影响我对其进行大量更改的优先级:)
This is not my code; it's code I have to work with, I'm interested in whether this is bad code or broken code as the different affects my priorities for changing it a great deal :)
标记 C 和 C++ .我主要对 C++ 感兴趣,但如果 C 不同,我也会感兴趣,只是为了兴趣.
Tagged C and C++ . I'm mostly interested in C++ but also C if it is different, just for interest.
推荐答案
这是非法的1.这是 C++ 中的未定义行为.
It is illegal 1. That's an Undefined behavior in C++.
您以数组方式获取成员,但这是 C++ 标准所说的(重点是我的):
You are taking the members in an array fashion, but here is what the C++ standard says (emphasis mine):
[dcl.array/1]::strong> ...数组类型的对象包含一个连续分配的非空 N 集合T 类型的子对象...
[dcl.array/1]: ...An object of array type contains a contiguously allocated non-empty set of N subobjects of type T...
但是,对于成员来说,没有这样的连续要求:
But, for members, there's no such contiguous requirement:
[class.mem/17]::strong> ...;实现对齐要求 可能会导致两个相邻的成员不要紧随其后分配...
[class.mem/17]: ...;Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other...
虽然上面的两个引号应该足以暗示为什么像您那样对 struct
进行索引不是 C++ 标准定义的行为,但让我们举一个例子:看看表达式 (&thing.a)[2]
- 关于下标运算符:
While the above two quotes should be enough to hint why indexing into a struct
as you did isn't a defined behavior by the C++ standard, let's pick one example: look at the expression (&thing.a)[2]
- Regarding the subscript operator:
[expr.post//expr.sub/1]:后缀表达式后跟方括号中的表达式是后缀表达式.表达式之一应是类型的泛左值T 数组"或指向 T 的指针"类型的纯右值,另一个应是无作用域枚举或整数类型的纯右值.结果是T"型.类型T"应是完全定义的对象类型. 66表达式 E1[E2]
与 ((E1)+(E2))
[expr.post//expr.sub/1]: A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall be a glvalue of type "array of T" or a prvalue of type "pointer to T" and the other shall be a prvalue of unscoped enumeration or integral type. The result is of type "T". The type "T" shall be a completely-defined object type.66 The expression
E1[E2]
is identical (by definition) to((E1)+(E2))
深入研究上面引用的粗体文本:关于将整数类型添加到指针类型(注意这里的重点)..
Digging into the bold text of the above quote: regarding adding an integral type to a pointer type (note the emphasis here)..
[expr.add/4]::strong> 当一个整数类型的表达式被添加到一个或从一个指针,结果具有指针操作数的类型.如果表达式P
指向数组对象x
的元素x[i]
对于 n 个元素,表达式 P + J
和 J + P
(其中 J
有值 j
) 指向(可能是假设的)元素 x[i + j]
如果 0 ≤ i + j ≤ n
;否则,行为未定义....
[expr.add/4]: When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression
P
points to elementx[i]
of an array objectx
with n elements, the expressionsP + J
andJ + P
(whereJ
has the valuej
) point to the (possibly-hypothetical) elementx[i + j]
if0 ≤ i + j ≤ n
; otherwise, the behavior is undefined. ...
注意if 子句的array 要求;else 上面引用中的否则.表达式 (&thing.a)[2]
显然不符合 if 子句的条件;因此,未定义行为.
Note the array requirement for the if clause; else the otherwise in the above quote. The expression (&thing.a)[2]
obviously doesn't qualify for the if clause; Hence, Undefined Behavior.
附带说明:虽然我在各种编译器上对代码及其变体进行了广泛的试验,但它们在这里没有引入任何填充,(它有效);从维护的角度来看,代码是极其脆弱的.在执行此操作之前,您仍然应该断言实现是连续分配成员的.并留在界内:-).但它仍然是未定义的行为......
On a side note: Though I have extensively experimented the code and its variations on various compilers and they don't introduce any padding here, (it works); from a maintenance view, the code is extremely fragile. you should still assert that the implementation allocated the members contiguously before doing this. And stay in-bounds :-). But its still Undefined behavior....
其他答案提供了一些可行的解决方法(具有定义的行为).
Some viable workarounds (with defined behavior) have been provided by other answers.
正如评论中正确指出的那样,[basic.lval/8],在我之前的编辑中不适用.感谢@2501 和@M.M.
As rightly pointed out in the comments, [basic.lval/8], which was in my previous edit doesn't apply. Thanks @2501 and @M.M.
1:请参阅@Barry 对此问题的回答,了解唯一一种可以通过此部分访问结构的 thing.a
成员的法律案例.
1: See @Barry's answer to this question for the only one legal case where you can access thing.a
member of the struct via this parttern.
这篇关于索引结构是否合法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!