C99 标准是否允许将变量分配给自己?例如,以下是否有效:
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
虽然我怀疑案例1是有效的,但我对于案例2犹豫不决。
在赋值的情况下,右侧在将值分配给左侧变量之前完全评估 - 或者是在解除引用指向变量的变量的指针时引入的竞争条件?
答案 0 :(得分:4)
这两种情况都是完全有效的,因为a
的值仅用于确定要存储的值,而不是用于确定要存储此值的对象。
从本质上讲,你必须区分三种不同的操作
这三个操作中的前两个操作可以按任何顺序完成,即使是并行操作。第三个显然是另外两个人的结果,所以它将会出现。
答案 1 :(得分:3)
这完全有效,您只使用之前的值来确定要存储的值。 draft C99 standard部分6.5.2
中介绍了这一点:
在前一个和下一个序列点之间,一个对象应该具有它 通过评估一次最多修改一次的储值 表达式。此外,先前的值应该只读 确定要存储的值。
有效代码的一个例子如下:
i = i + 1;
C和C ++部分here涵盖了序列点可能发生的不同位置。
答案 2 :(得分:2)
假设编译器没有通过简单地删除它来优化第一条指令,那么这里甚至存在竞争条件。在大多数体系结构中,如果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>
答案 3 :(得分:2)
C99 6.5.16.1简单分配
3如果从另一个以任何方式重叠的对象读取存储在对象中的值 存储第一个对象,然后重叠应该是精确的,两个对象应该是 具有兼容类型的合格或不合格版本;否则,行为是 未定义。
我认为示例代码限定了“重叠”条件。由于它们具有兼容类型的合格版本,因此结果有效。
另外6.5.16分配操作员
4未指定操作数的评估顺序。如果尝试修改 赋值运算符的结果或在下一个序列点之后访问它 行为未定义。
但是,没有“尝试修改结果”,因此结果是有效的。
答案 4 :(得分:0)
我看不到C编译器不允许a = a
。由于宏没有程序员知道它,这种分配可能偶然发生。它可能甚至不会生成任何代码,因为这是一个优化问题。
#define FOO (a)
...
a = FOO;
示例代码很容易编译,我对C标准的审查没有禁止。
关于比赛条件@Yu Hao回答得很好:没有比赛条件。