【问题标题】:What does if((x=0)) mean in C?if((x=0)) 在 C 中是什么意思?
【发布时间】:2014-09-21 15:06:22
【问题描述】:

显然,在 gcc/C 中,编译器何时编译

if ((x=0)){ some code }

被使用,而当

if (x=0){ some code }

被使用,然后编译器拒绝编译。

两者有什么区别?

作为说明,我知道x==0x=0 之间的区别。我只是在探索 C 遇到一些奇怪的代码时的行为。

【问题讨论】:

  • 我不明白为什么有人会想要做if ((x=0)) {...},因为那个条件总是错误的。 (或x=N 为任何常量N。)如果这是您在野外遇到的代码,可能有人试图在不了解警告的目的的情况下抑制警告。
  • 顺便说一句,一个简单的技巧可以帮助检测许多使用 = 代替 == 的情况,即始终将常量放在左侧——'if(0=x)' 将产生一个不能赋值给常量的错误。
  • @keshlam 也称为Yoda conditions
  • 也被称为降低代码的可读性,因为你害怕你不知道如何输入。 :)
  • 哪个版本的 GCC 和哪些开关?对于 -Wall,Red Hat 4.8.3-1 建议 在赋值周围使用括号作为真值,但它编译得很好......

标签: c gcc gcc-warning


【解决方案1】:

在代码方面没有区别。

所有发生的事情是说x=0 而不是x==0 是一个常见的错误,大多数编译器在看到它时会发出警告(或错误,在你的情况下)。额外的一组括号是关闭编译器的常用技巧 --- 相当于说“是的,我真的打算这样做”。

【讨论】:

  • 恐怕除了“因为他们不想要它”之外没有什么好的答案。额外的括号集现在无处不在,可以告诉编译器抑制它现在可能不会改变的警告。
  • @LưuVĩnhPhúc:您明确表示您知道自己在做什么,= 不是错字。
  • @wildplasser -- 普通并不意味着每次都是同一个人。
  • @wildplasser: ...以及任何不小心双击=的专家。或者只是犯了一个短暂的心理错误。
  • @wildplasser 除了 Rob 和 Hurkyl 刚才所说的之外,您还假设历史上唯一的新手程序员是十年前的您,并且不存在更多的新手程序员现在也不会有。
【解决方案2】:

两者都是语法正确的 C,编译器必须处理它。但是编译器可能会根据配置发出警告甚至错误(例如 gcc 中的 -Werror),因为其中一个非常可疑,以至于您永远不会认为它是故意的。当您使用 if (x = 0) { ... } 之类的东西(将零分配给 x 并在零非零时运行该块)时,您几乎总是实际上是指 if (x == 0) { ... }(如果 x 为零则运行该块)。

现在让我们来看看为什么 if ((x = 0)) { ... } 不被认为足够可疑以保证 相同类型的警告(这个特定的代码仍然是可疑的,因为条件总是计算为零并且主体永远不会运行)......

一些 C 开发人员(我就是其中之一)使用的一种习惯用法是将赋值放在括号中,并利用即使赋值本身也有一个值并且它是赋值的特性。

例子:

#include <stdio.h>

int main(int argc, char **argv)
{
    int c;

    while ((c = getchar()) != '\n')
            printf("Character: '%c' (0x%02x)\n", c, c);

    return 0;
}

测试示例:

$ ./test
Hello!
Character: 'H' (0x48)
Character: 'e' (0x65)
Character: 'l' (0x6c)
Character: 'l' (0x6c)
Character: 'o' (0x6f)
Character: '!' (0x21)

重要的部分是条件(c = getchar()) != '\n',您首先将getchar() 的结果分配给c,然后检查它的特定值。在这种情况下,我们从标准输入一个接一个地读取字符,直到一行的 and (技术上,直到我们读取一个 \n 字符)。这样做的主要优点是它允许您将getchar() 填充到测试中。否则,您将不得不使用逗号符号、带中断的无限循环,或者将其放在循环之前和循环末尾。

有时您会与非零值进行比较,例如\n-1 等,但有时您会与零进行比较,或者在使用指针时与NULL 进行比较。让我们为NULL 找一个例子,这在内存分配中很常见。

char *p;

if ((p = malloc(50)) == NULL) {
    ...handle error...
}

当然可以这样写:

char *p;

p = malloc(50);
if (p == NULL) {
    ...handle error...
}

但根据您的口味,您也可以使用:

char *p;

if (!(p = malloc(50))) {
    ...handle error...
}

或者甚至反过来(顺便说一句,这违背了 my 总是首先处理错误情况的偏好):

char *p;

if ((p = malloc(50))) {
    ...do stuff...
} else {
    ...handle error...
}

在最后一种情况下,条件是(p = malloc(50)),它完全等同于p = malloc(50),但后者非常可疑,因为已经提到的常见错误是在C中执行赋值而不是比较和派生语言。请注意,这不仅与可疑编译器有关,还与人类阅读代码和查看潜在错误有关。

多余的括号只是告诉读者和编译器这个赋值绝对是故意的,而不是那个常见错误的发生。

【讨论】:

  • 一个符合 C编译器可能不会拒绝if (x = 0)if ((x = 0))。它可能会警告它喜欢的任何东西,包括你穿的那件衬衫。
  • @PavelŠimerda:关键是编译器可以警告他们喜欢的任何事情。
  • @PavelŠimerda:不,我提出了一个重要且有效的观点(带有一点幽默感)。
  • @PavelŠimerda:将评论阅读为“标准将允许编译器警告它喜欢的任何事情——即使是 C 编译器不应该关心的事情——只要警告不'不要阻止编译符合标准的程序”。请注意,-Werror 选项要求编译器以与标准相反的方式运行,但对许多程序员来说更有用。
  • 任何称职的编译器都应该警告夏威夷衬衫。
【解决方案3】:

除非您拥有-Werror,否则代码不应“拒绝”编译。如果您启用了警告,它可能会告诉您:

警告:建议在赋值周围使用括号作为真值 [-W括号] while (*dest++ = *src++)

具体来说,GCC docs 说明了警告的目的:

在某些情况下省略括号时发出警告,例如当 在期望真值的上下文中存在分配, 或者当操作符嵌套时,人们经常得到优先级 困惑。

【讨论】:

    猜你喜欢
    • 2014-11-06
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2019-12-08
    • 2012-04-17
    • 1970-01-01
    相关资源
    最近更新 更多