C99标准是否允许将变量分配给自己?例如,以下是否有效:
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
虽然我怀疑案例 1 是有效的,但对于案例 2,我很犹豫。
在赋值的情况下,在将值分配给左侧的变量之前,右侧是否已完全评估- 或者在取消引用指向被分配变量的指针时是否引入了竞争条件?
C99标准是否允许将变量分配给自己?例如,以下是否有效:
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
虽然我怀疑案例 1 是有效的,但对于案例 2,我很犹豫。
在赋值的情况下,在将值分配给左侧的变量之前,右侧是否已完全评估- 或者在取消引用指向被分配变量的指针时是否引入了竞争条件?
这两种情况都是完全有效的,因为 的值a
仅用于确定要存储的值,而不是确定要存储该值的对象。
本质上,在作业中,您必须区分三种不同的操作
这三个操作中的前两个可以按任何顺序进行,甚至可以并行进行。第三个显然是其他两个的结果,所以它会在之后发生。
假设编译器没有通过简单地删除第一条指令来优化它,这里甚至存在竞争条件。在大多数架构上,如果 a 存储在内存中,a = a
将在两个移动指令中编译(mem => reg,reg => mem),因此不是原子的。
这是一个例子:
int a = 1;
int main()
{ a = a; }
在带有 gcc 4.7.1 的 Intel x86_64 上的结果
4004f0: 8b 05 22 0b 20 00 mov 0x200b22(%rip),%eax # 601018 <a>
4004f6: 89 05 1c 0b 20 00 mov %eax,0x200b1c(%rip) # 601018 <a>
C99 6.5.16.1 简单赋值
3 如果存储在一个对象中的值是从另一个对象读取的,该对象以任何方式与第一个对象的存储重叠,则重叠应准确,并且两个对象应具有兼容类型的合格或不合格版本;否则,行为未定义。
我认为示例代码符合“重叠”条件。由于它们确实具有兼容类型的合格版本,因此结果是有效的。
还有 6.5.16 赋值运算符
4 操作数的求值顺序未指定。如果尝试修改赋值运算符的结果或在下一个序列点之后访问它,则行为未定义。
尽管如此,没有“尝试修改结果”,所以结果是有效的。
我看不到 C 编译器不允许a = a
. 这种分配可能由于程序员不知道的宏而偶然发生。它甚至可能不会生成任何代码,因为这是一个优化问题。
#define FOO (a)
...
a = FOO;
示例代码很容易编译,我对 C 标准的审查表明没有禁止。
至于比赛条件@Yu Hao 回答得很好:没有比赛条件。