2012-08-26 58 views
2

正如标题所说,我在一些C讲义中找到了这样一个句子。算术赋值运算符 - 左侧仅评估一次

我不能发明任何证明这句话的例子。

在我看来,每一次赋值操作都会被评估一次,因为当我们希望对它进行多次评估时,我们会将其放入一个循环中。那么我错过了什么?

我已经搜索,但在这里找不到答案。

+0

的例子吗?我不明白.. –

+0

没有任何实际解释问题的任务,与例如相反。 'x + = 6' –

+0

请参见[C++中| =运算符的含义](http://stackoverflow.com/questions/4217762/what-does-the-operator-mean-in-c/4217772#4217772)虽然它是针对C++的,但它的确解释了对运营商的LHS进行一次评估意味着什么。除了提及运算符重载(仅限于C++),注释适用于C和'+ ='(和'| ='和其他赋值运算符)。 –

回答

6

Ç说:

(C99,6.5.16.2p3)仅在该左值形式E1 OP = E2从简单赋值表达式E1 = E1 OP(E2)的不同的“A化合物分配E1只评估一次。“

下面是为什么它的问题的一些例子:

实施例1:

a[i++] += 1; 

相同:

a[i] = a[i] + 1; i++; 

由于+=左操作数是评估一次。

如果不是计算一次这将是一样的:

a[i++] = a[i++] + 1; 

这当然是不同的(和未定义的行为BTW)。

实施例2:

*foo() += 1; 

foo假设这里返回一个指向标量类型的对象,并产生副作用(例如它打印在终端上的字符串)。使用复合赋值运算符时,它只会打印一次而不是两次。

实施例3:

REG |= 0x01; 

REG假设这里是一个IO寄存器(像#define REG (*(volatile uint8_t *) 0x42))和每读取该特定IO寄存器触发硬件事件。该寄存器只能用复合赋值操作符读取一次,而不能两次。

编辑:以下@R.评论我删除线的例子3.我想大多数编译器不会在这个表达式执行读:REG = 31或两个与该表达式如下:REG = REG | 0x01

+0

示例3不正确。无论您是分别使用'| ='或'|'和'=',寄存器都将被精确读取一次,并且只写入一次。这是因为左值引用的对象不是作为评估'='运算符的一部分读取的。也许你想到的是''=''可能会在'|'和'='单独执行时执行单指令读 - 修改 - 写周期,但我认为这个假设是错误的; volatile并不要求,并且可能不会(在严格阅读对volatile的要求下)甚至允许它。 –

+0

@R。例3我可能太快了,因为它不符合现实世界的例子。实际上,大多数编译器可能不会像'REG = 31'这样的简单赋值来进行读操作(例如http://gcc.gnu中的'vobj1')。org/wiki/VolatileAccessComparison)。但我认为编译器可以执行它。我无法看到C语言标准的观点与此语句有所不同:'REG;'该值也未被使用,但大多数编译器执行读取操作。 – ouah

+0

@R。顺便谢谢你的评论,我编辑了我的答案。 – ouah

1

你的问题很不明确,措辞也不太好,但我怀疑你的笔记提到的是,组合的算术+赋值运算符允许你做某些事情而不用写(并因此评估)左值的表达式比一次。例如,

*p++ += *q++; /* p is incremented once, as desired */ 
*p++ = *p++ + *q++; /* undefined behavior */ 

这尤其重要,当你在宏来使用这些,例如:

#define ACCUM(d,s) (d)+=(s) /* good */ 
#define ACCUM(d,s) (d)=(d)+(s) /* dangerous */ 
0

不要有什么编译方便,但这里是一个有趣的花絮:

var1 += var++将VAR1的值更改为var1 + var

然而

var1 += ++var将VAR1的值更改为var1 + (var + 1)

+0

我认为这是问题中的理解(或不是问题);问题是什么意味着这个任务的LHS被评估一次 - 为什么(或什么时候)这个关键? –

+1

哦,我的错误我想我完全错过了这个问题的观点。 –

0

有一些化合物分配操作在下例如+ =, - =,* =,/ =,%=

例如, i + = 1它将i的值增加1,如i ++。

+0

我认为这是在问题中理解;问题是什么意味着这个任务的LHS被评估一次 - 为什么(或什么时候)这个关键? –

+0

我已经熟悉你写的东西,而不是我在这里问的情况。无论如何感谢活动;) –

2

通常+=操作员通过以下方式介绍:

x += y; 
x = x+y; // does the same 

但是,该说明试图告诉你,这其实不准确,为=左侧,+=可能是任何表达。正如其他人所说,这可能导致未定义的行为,但这不是问题的核心。

例如:

char* f() { 
    static char value = 'a'; 
    printf("%c\n",value); 
    return &value; 
} 

void g() { 
    *f() = 'b'; // assigns 'b' which was 'a' 
    *f() += 2; // changes 'b' to 'd' 
    *f() = 'b'; 
    *f() = *f() + 2; // changes 'b' to 'd' 
} 

的区别在于f在最后一行,同时它在第二执行一次执行两次。

+0

+1不错的说明示例。 –

0

有复合赋值运算符的数目。例如。 +=,-=,*=,/=,%=

a+=bgive a=a+b 了解更多详情请点击this