【问题标题】:while(foo) vs while(foo != NULL)while(foo) 与 while(foo != NULL)
【发布时间】:2015-06-02 22:53:17
【问题描述】:

有人能解释一下while(foo)while(foo != NULL) 是如何等价的吗?另外:

while(!foo)while(foo == NULL)

我知道!不是,但这就是我所知道的。

【问题讨论】:

标签: c while-loop


【解决方案1】:

只要expression 评估为任何非零值,while (expression) 就会重复封闭块。当expression 计算为 0 时,while 循环结束。

如果指针值不是std::nullptrNULL,则指针类型的expression 被认为是非0。

! 运算符是布尔型 not 运算符。

因此

 while (foo)

 while (foo != NULL)

在逻辑上是等价的。因此,两者的逻辑逆也等价。

【讨论】:

  • std::nullptr 是 C++ 的东西。我们有一个 [c] 问题。
【解决方案2】:
while(foo);

while(foo != NULL)

是等价的,因为 NULL 是一个扩展为 0(void*)00L 的宏,假设在 C 0 中计算结果为 false(并且任何非零数为 true)然后

while(foo); //while foo isn't 0
while(foo != NULL) //expands to while(foo != 0) < while foo isn't 0

【讨论】:

  • 取决于foo 的类型。考虑double foowhile(foo); 可以,但 while(foo != NULL) 无法编译:“二进制!= 的无效操作数”取决于NULL 的定义方式,它应该是一个空指针常量,而不是这里建议的0
  • @chux 当然,这是假设foo 是指针或int 但是NULL 保证比较等于0,实际上我认为大多数实现确实使用0 作为@ 987654337@.
  • "大多数实现确实使用 0 作为 NULL" 不同意,我的 gcc 4.9.2 使用 #define NULL ((void *)0)。 MS Visual 2010 编译为C 时使用#define NULL ((void *)0)。也许您正在考虑如何用另一种语言定义 NULL,例如 C++
  • @chux 我在回答中说过“NULL 是一个扩展为 0 或 (void*)0 或 0L 的宏”
  • 我断言NULL 可以是(void*)0,但不是0,也不是0L。您的回答表明它可能是0, or (void*)0 or 0L。您评论“大多数实现确实使用 0 作为NULL”,没有任何示例支持,而给出了 2 个反例。
【解决方案3】:

while 循环可以这样运行:

while(1) //This will run forever.

while(true) //This will run forever.

NULL 就像 0,所以如果你有 while(foo != NULL),这就是说 while(foo 不等于 0,所以 while 它等于 1 或其他东西) 运行它。

【讨论】:

    【解决方案4】:

    NULL 是一个符号常量,你可以把它看作是一种替换文本。 NULL 只是编译器稍后用零替换的东西,所以写while (foo != NULL) 和写while (foo != 0) 是一样的。请记住,== 表示是,如果它的左边等于它的右边,而!= 表示是,如果它的左边不等于它的右边。

    在 C 语言中,数字 0 总是表示假,其他数字表示真。所以while (foo != 0) 与说“在 foo 为真时运行此循环中的代码”相同。例如,while (1) 与“永远运行此循环中的代码”相同,因为 1 是一个始终不为零的数字,因此始终为真。

    在 C 语言中,如果你只使用 foo 来表示一个真或假类型的值,这与说 foo != 0 相同,这有点像你可以使用的快捷方式,这与询问相同“foo是真的吗?”。 ! 表示“不”,所以问!foo 与问“foo 不是真的吗?”是一样的,换句话说,“foo 是不是假的?”。这意味着while (!foo) 与“在 foo 为 false 时运行此循环中的代码”相同,与 while (foo == 0) 相同,因为零表示错误,与 while (foo == NULL) 相同,因为 NULL 表示零.

    这样想:循环中的代码只有在括号中的内容为真(即非零)时才会运行。所以在while (foo) 中,计算机会问“foo 是否非零?”,如果是,则循环继续。现在,如果您有while (!foo),计算机会询问“foo 不是非零吗?”,如果是,则循环继续。仅当括号中的表达式为 false 时,循环才会停止。

    NULL在几个标准头文件中都有定义,它不是ifwhile这样的关键字,你需要包含一个定义它的头文件才能使用它。这个想法是,当指针指向地址零时,它被称为“空指针”,这就是为什么它被称为NULL,当你想说“将地址归零”而不是仅仅“将数字归零”时使用它。

    编辑: 正如 Matt McNabb 正确指出的那样,NULL 可以定义为0(void *)0。为避免任何疑问,我引用 C11 标准:

    值为 0 的整数常量表达式,或转换为 void * 类型的表达式称为 空指针常量

    后来

    NULL (和其他头文件)中定义为空指针常量;见 7.19。

    那么,在第 7.19 节中:

    3 宏是

    扩展为实现定义的空指针常量;和

    offsetof(type, member-designator)

    扩展为...

    然后文字继续。所以(void *)00 是有效的实现定义的空指针常量。

    【讨论】:

    • NULL 可以是0(void *)0
    • @Matt McNabb NULL 可以是 0 吗?当我阅读 C 规范时,NULL 是一个“空指针常量”。 0int。也许相同的值,但不同的类型和大小。
    • @chux 然后继续定义null pointer constant 是一个整数常量,等于零或与void* 相同。
    • @danieltm64 用 a3f 得出结论,Matt McNabb 正确的 NULL 可能是 0(void *)0
    【解决方案5】:

    假设foo 是指针类型,while (foo)while (foo != NULL) 完全等价。两者也等价于while (foo != 0)。 (在我看来while (foo != NULL)更清楚地表达了意图。)

    在任何需要条件的上下文中(if()while()、其他一些),如果条件比较不等于零,则表达式被视为 truefalse em> 如果比较等于零。

    NULL 是一个扩展为实现定义的空指针常量 的宏。将指针值与NULL 进行比较会产生空指针的真值,任何非空指针的假值。

    常量0 是一个空指针常量[*]。 (这并不意味着空指针具有与 0x00000000 或类似的相同的位表示,尽管它经常这样做;这意味着常量 0 在源代码中可以表示空指针。)如您所料,将指针值与空指针常量进行比较会告诉您该指针是否为空指针。在while (foo) 中,与零的比较是隐式的——但它仍然测试foo 是否为空指针。

    更一般地说,while (foo)foo0 进行比较,这相当于将其与适当类型的“零”进行比较。 while (foo) 始终等同于 while (foo != 0)。对于浮点值,它也等价于while (foo != 0.0)。对于字符值,它相当于while (foo != '\0')。而且,正如我们所见,对于指针值,它等价于while (foo != NULL)

    (在 C 中,比较运算符总是产生 int0 如果条件为假,1 如果条件为真 - 但任何非零值都被视为真,通过隐式不等式与零比较。)

    [*] 空指针常量 被定义为具有值0 的整数常量表达式,或者这样的表达式转换为void*。空指针常量不一定是指针类型,但将其转换为指针类型会产生空指针值。将指针值与0 进行比较会导致0 隐式转换为指针类型,以便进行比较。

    【讨论】:

    • @chux:已更新。 (0 既是 int 类型的表达式,又是一个空指针常量;我知道这可能会引起混淆。)
    • 是的,它对我有用,我享受crow 的午餐。事实证明#define NULL 0#define NULL ((void*)0) 一样有效。后者有优势,但两者都合规。
    • @chux:有一个模糊的论点是 #define NULL ((void*)0) 无效。 (N1570 6.5.1p5 并没有说带括号的空指针常量是空指针常量。)但实际上它肯定是有效的。
    猜你喜欢
    • 1970-01-01
    • 2014-12-01
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2010-12-12
    • 2016-09-19
    • 1970-01-01
    相关资源
    最近更新 更多