2010-08-17 86 views
29

我有必要代码的形式为什么C没有逻辑赋值运算符?

a = a || expr; 

其中expr应评估和结果分配给a当且仅当a没有设置的声明。这依赖于逻辑OR的短路能力。

写上面会,当然是

a ||= expr; 

但较短的方式(让我吃惊的)C没有逻辑赋值运算符。

所以我的问题是双重的。首先,在标准C中写出第一条语句的方法更短(三元运算符更糟糕 - a = a ? a : expr要求我拼出a三倍)。

其次,为什么C中没有逻辑赋值?我能想到的可能原因有:

  • 它使语法难以解析?
  • 处理这些情况下的短路有一些微妙之处吗?
  • 它被认为是多余的(但不是反对所有运营商分配的争论?)

编辑

请解开这个问题,因为:

  • 它被连接到的问题(作为所谓的重复)尚未得到答复。该问题的(接受的)答案指出||=不存在,因为重复了|=的功能。这是错误的答案。 |=不会短路。

  • C和C++不是相同的语言。我想知道为什么C没有它。事实上,像C++这样的派生语言,特别是Java(它没有像Edmund的答案中提到的遗留代码的问题)的事实使得这个问题更加有趣。

EDIT 2

现在好像我的原意是错误的。在声明a = a || expr(其中a是整数,expr返回一个整数值,首先将aexpr隐式转换为“布尔值”,然后将“布尔值”值分配给a。这将不正确 - 整数价值将会丧失。谢谢,延斯和埃德蒙。

因此,对于问题的第一部分,正确的方式,而不是替代品:),编写我的意图是:

if (!a) a = expr; 

a = a ? a : expr; 

他们应该优化相同(我认为)虽然个人我宁愿第一个(因为它有一个a键入)。

但是,问题的第二部分仍然存在。 Jens和Edmund关于a ||= expr中含糊不清的论点同样适用于a = a || expr。分配情况下,可以简单地被视为正常之一:

  • 转换a为布尔
  • 如果这是真的,则整个表达式的值变为等于a
  • 布尔值否则评估expr ,将结果转换为布尔值,分配给a,并将其返回

以上步骤似乎对于赋值和正常情况都是相同的。

+1

此问题*不是*上述“可能重复”的确切副本。那个问题问为什么没有'|| ='的语法缩写,等等。这个问题询问为什么C不允许通过布尔运算符来携带非布尔运算符。 – Edmund 2010-08-17 09:41:43

+1

我打算发表一个答案:如果那些短路工作会很好。 有一个选项'if(!a)a = expr;'这个选项很清楚简洁。 至于技巧,请注意,布尔的加法和乘法分别产生OR和AND函数,只要你不需要短路或强制转换为'bool','+ ='和'* ='分别执行'|| ='和'&& ='。 – Potatoswatter 2010-08-17 09:43:10

+1

由于这是过早关闭,我在评论中回答。我认为这不存在,因为它的解释是不明确的。在'a | = expr'中应该赋值'expr'的结果还是其逻辑值? “a | = expr”的整体类型,“int”,“a”的类型或者“a”和“expr”的结果应该是什么?我不认为这些问题有一个直接的解决方案,所以任何可能已经考虑过这个问题的人都已经很快放弃了。我个人会选择'a =(a?a:expr)'并让编译器优化分配。 – 2010-08-17 12:44:57

回答

3

我想简单的答案是||是一个布尔运算符:在C中,“布尔值”是0或1.操作数隐式转换为布尔值(我没有检查过这是规范实际说的,但它是C的行为),结果是一个布尔值。

改变语义以支持这种模式可能是可行的 - 直到有人依靠||来完成它始终完成的任务。

+3

C中没有'boolean'类型,所以操作数不会被转换为'boolean','||'的结果并且'&&'不是'boolean'。 – qrdl 2010-08-17 10:08:22

+2

@qrdl关于'boolean'(虽然C99具有'_Bool'),但'&&','||'(和'!')被定义为0或1的情况是对的。请参阅C99标准§6.5 .13和§6.5.14。 – schot 2010-08-17 10:47:17

+1

谢谢。我使用“引号”表示这就是它的近似含义。如果我想要bean指的是神秘的'boolean'类型,我就会这样表示它。我的答案整体而言表现为行为,而不是抽象的规范。 – Edmund 2010-08-17 10:59:38

3

由于运算符||&&的返回类型与其左侧参数的类型不同。

||&&返回类型总是int ,而左边的参数可以是任何一体的,浮点或指针类型。操作数也不必是同一类型的。因此将x ||= y定义为x = x || yx &&= yx = x && y与其他扩充分配一致将不能将结果存储在大多数类型的参数中。

你可以想出其他的定义,例如x ||= y作为if(!x) x = yx &&= y作为if(!y) x = y,但那不会很明显,它不是有用,所以它不包括在内。

在C++中,它是bool

3

我找不到任何特殊的原因,为什么运营商不存在(在C99)。

所以我能找到的唯一原因是,在C89中没有布尔类型,而这些布尔运算符仅用于if's。

例子:

int i = 5; 

/* This should not make any difference, 
    since or'ing with false, shouldn't change 
    the value... dib di dib diddy...*/ 
i ||= 0; /* Actually: i = i || 0, which gives 'true' */ 

i现在是'1”,这对于大多数人来说是相当直觉。

这个操作符显然不带任何清除或编码改进没有布尔类型,这将使​​认识或与另一个。

在我看来,a ||= b;作为if(!a) a = b;的实施将是非常简单的,并已通过例如实现。 Lua中。

所以你的问题似乎有点,为什么C被设计了它的方式。 如果这个问题是关于C++的,那么你可以问Bjarne Stroustrup并问他到底是怎么回事。既然事实并非如此,那么在我看来,这似乎是一种死路一条,因为标准已经写得相当一段时间了,而且你不能再问人了,为什么要这样做。另一方面,这个不完整的操作符集应该(在我看来)aleardy已经使用了与你的类似的符号整体,因为在我看来,没有任何理由反对它。

我希望我能帮一点点。

5

a ||= expr由于其等价物a = a || expr的短路评估而存在问题。

要有a ||= expr功能像a = a || expr考虑OP的断言:

“在声明中a = a || expr ...,第一a和EXPR将被隐式转换为 ”布尔“,”

这是不正确的。 expr将不会被转换,如果a评估为true。如果expr类似于scanf()rand()或某些影响程序状态的函数,这将会产生变化。

诸如a ||= scanf("%d", &i) != 1;之类的代码只会尝试在a中扫描具有错误值的数据。尽管可以用这种方式来扩展语言,但是对当前的||&&集合的其他短路操作可能会导致比明确简化更多的编码问题。

另一方面:一种快速(如果模糊处理)编写代码的方法,其中函数在出错时返回非零代码。

// Perform functions until an error occurs. 
bool error = foo1(); 
error &&= foo2(); // Only valid if C was extended with &&= 
error &&= foo3();