2013-07-17 49 views
2

C99标准是否允许将变量分配给自己?举例来说,有以下几种有效:C99标准是否允许为自己分配一个变量?

int a = 42; 

/* Case 1 */ 
a = a; 

/* Case 2 */ 
int *b = &a; 
a = *b; 

虽然我怀疑病例1是有效的,我很犹豫,说同样的情况2

在转让的情况下,是右侧完全评估之前将值分配给左侧的变量 - 或者是取消引用指向所分配的变量的指针时引入的竞争条件?

+1

'a = a;'是高级语言中的死指令,我非常肯定优化阶段会将其删除 –

+1

@GrijeshChauhan并不总是如果a在内存中并且不需要优化。看我下面的例子。 – hivert

+2

只要变量已经正确初始化,你应该没问题。如果变量未初始化,则复制未初始化的值不会使其更好地初始化。如果变量是volatile,它可能不是空操作(编译器必须读取该值并写入再次读回的值)。当变量不符合volatile时,它应该是no-op。 –

回答

4

两种情况都是完全有效的,因为a的值仅用于确定要存储的值,而不是确定要存储该值的对象。

在你必须区分三种不同的操作

  • 确定到的值是要被存储
  • 评价RHS
  • 存储在所确定的对象所确定的值的对象的分配本质

这三个操作中的前两个操作可以以任何顺序完成,即使并行。第三个显然是另外两个的结果,所以它会出现。

3

这是完全有效的,你只使用以前的值来确定要存储的值。这是包括在draft C99 standard6.5.2它说:

之前和下一序列点之间的对象应具有由 expression.Furthermore的评价中,前一个值改性至多一次其 储值只读为 确定要存储的值。

之一的有效代码的示例如下:

i = i + 1; 

C和C++部here涵盖可以发生的序列点不同的地方。

2

假设编译器不会通过简单地删除第一条指令来优化第一条指令,这里甚至存在竞争条件。在大多数体系结构中,如果a被存储在内存中,a = a将被编译为两条移动指令(mem => reg,reg => mem),因此不是原子性的。

下面是一个例子:

int a = 1; 
int main() 
{ a = a; } 

在Intel x86_64的用gcc结果4.7.1

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> 
+0

但你是*假设*,你试过吗?为什么没有任何编译器不能删除它?它很容易做到检测。这是你真实的例子吗?哪个编译器? –

+0

虽然@GrijeshChauhan可能是正确的,现代编译器很可能不会这样做,但我对C99标准是否允许这种行为感兴趣 - 毕竟,编译器不必*实用*成为*符合标准*。 –

+0

hmm hivert推出了它会是如果编译器不优化它,所以它的好答案。 –

2

C99 6.5.16。1简单赋值

3如果被存储在一个对象的值是从以任何方式 第一个对象的存储重叠的另一目的读取,则重叠应为精确和两个对象应 有资格或兼容类型的非限定版本;否则,行为是未定义的 。

我认为示例代码限定了“重叠”条件。由于它们具有兼容类型的限定版本,因此结果是有效的。

另外6.5.16赋值运算符

4的操作数的评价的顺序是不确定的。如果尝试修改赋值运算符的结果或在下一个序列点之后访问它,则 行为未定义。

仍然没有“尝试修改结果”,所以结果是有效的。

+0

关于段落4('如果试图修改赋值操作符的结果或在下一个序列点之后访问它,行为是未定义的。因为'a'在评估之前被修改:'a = ++ a'?什么是*序列点*? –

+1

@VilhelmGray这是一个关于序列点的很好的参考:http://en.wikipedia.org/wiki/Sequence_point它有一个关于C和C++的部分,什么是序列点。 –

+0

@VilhelmGray是的,这是正确的,幻灯片197有这个例子:http://www.slideshare.net/olvemaudal/deep-c和这个页面有更多这样的例子:https://www.securecoding.cert.org /confluence/display/seccode/EXP30-C.+Do+not+depend+on+order+of+evaluation+between+sequence+points –

0

我看不到C编译器而不是允许a = a。由于没有程序员知道它的宏,这种分配可能偶然发生。它甚至可能不会生成任何代码,这是一个优化问题。

#define FOO (a) 
... 
a = FOO; 

示例代码很容易编译,我对C标准的审查显示不禁止。

至于比赛条件@于皓回答得好:没有比赛条件。

相关问题