代码之家  ›  专栏  ›  技术社区  ›  Ande Turner

C:与空的比较

  •  21
  • Ande Turner  · 技术社区  · 16 年前

    抛开宗教争论:

    • 选项1:

      if (pointer[i] == NULL) ...
      
    • 选项2:

      if (!pointer[i]) ...  
      

    在C中,选项1在功能上是否等同于选项2?

    由于没有比较,后期解决的更快吗?

    11 回复  |  直到 12 年前
        1
  •  15
  •   Tony Vijay    12 年前

    我喜欢第二个,其他人喜欢第一个。

    实际上,比起第一种,我更喜欢第三种:

    if (NULL == ptr) {
       ...
    }
    

    因为那时我:

    • 不会错过,只需键入一个“=”
    • 如果条件长(多行),则不会错过“==null”,并将其错误地改为相反的值。

    它们在功能上是等效的。

    即使是 NULL 指针不是“0”(所有零位), if (!ptr) 无效的 指针。

    以下内容不正确。它仍然在这里,因为有很多评论提到它: 不过,不要将指针与文本零进行比较。它几乎可以在任何地方工作,但它是未定义的行为IIRC。

        2
  •  33
  •   Laserallan    16 年前

    我更喜欢显式风格(第一版)。很明显,它涉及到一个指针,而不是一个整数或其他什么东西,但它只是样式问题。

    从性能的角度来看,它应该没有什么区别。

        3
  •  30
  •   Norman Ramsey    16 年前

    当量。在语言标准中是这样说的。人们有 该死的 宗教偏好!

        4
  •  19
  •   Stack Overflow is garbage    16 年前

    假设编译器编写者至少具有最少的智能通常很有用。你的编译器是 写的是一只小鸭子。它是由人类编写的,具有多年的编程经验和多年学习编译器理论的经验。这并不意味着你的编译器是完美的,并且总是知道最好的,但是它 这意味着它完全能够处理琐碎的自动优化。

    如果这两个表单是等效的,那么为什么编译器不将一个表单转换为另一个表单以确保两个表单的效率相同呢?

    如果 if (pointer[i] == NULL) if (!pointer[i]) 编译程序不会把它改成第二种更有效的形式吗?

    所以不,假设它们是等价的,它们同样有效。

    对于问题的第一部分,是的,它们是等价的。语言标准实际上在某个地方显式地声明了这一点——如果指针非空,则其计算结果为真;如果指针为空,则其计算结果为假,因此两者完全相同。

        5
  •  9
  •   Barry Kelly    16 年前

    几乎可以肯定,在性能上没有区别。不过,我更喜欢第二种含蓄的风格。

        6
  •  3
  •   Mark Rushakoff    16 年前

    NULL 应在标准头文件中声明,如:

    #define NULL ((void*)0)
    

    所以不管是哪种方式,您都要与零进行比较,编译器应该以相同的方式对两者进行优化。每个处理器都有一些“优化”或操作码与零进行比较。

        7
  •  1
  •   shimpossible    16 年前

    早期的优化是不好的。微优化也是不好的,除非你试图从你的CPU挤出每一个赫兹的最后一位,否则没有意义。正如人们已经展示的,编译器无论如何都会优化大部分代码。

    最好让代码尽可能简洁易读。如果可读性更强

    if (!ptr)
    

    比这个

    if (NULL==ptr)
    

    然后使用它。只要所有阅读你的代码的人都同意。

    我个人使用完全定义的值(空==ptr),所以很清楚我在检查什么。也许打字的时间更长,但我能很容易地读出来。我会想到的!PTR很容易错过!如果要快速阅读。

        8
  •  0
  •   Thomas Lee    16 年前

    它实际上取决于编译器。如果大多数现代C编译器没有为您描述的特定场景生成几乎相同的代码,我会感到惊讶。

    让编译器为每个场景生成一个程序集列表,然后您可以回答自己的问题(对于特定的编译器:)。

    即使他们 不同的是,性能差异在实际应用中可能无关紧要。

        9
  •  0
  •   Charles Ma    16 年前

    打开编译器优化,它们基本上是相同的

    在GCC 4.3.3中对此进行了测试

    int main (int argc, char** argv) {
       char c = getchar();
       int x = (c == 'x');
       if(x == NULL)
          putchar('y');
       return 0;
    }
    

    VS

    int main (int argc, char** argv) {
       char c = getchar();
       int x = (c == 'x');
       if(!x)
          putchar('y');
       return 0;
    }
    
    
    gcc -O -o test1 test1.c
    gcc -O -o test2 test2.c
    
    
    diff test1 test2
    

    未生成输出:)

        10
  •  -2
  •   ctennis    16 年前

    我做了一个组装转储,发现两个版本之间的区别:

    @@ -11,8 +11,7 @@
    pushl %ecx
    subl $20, %esp
    movzbl -9(%ebp), %eax
    - movsbl %al,%eax
    - testl %eax, %eax
    + testb %al, %al

    看起来后者实际上生成了一条指令,第一条生成了两条指令,但这是不科学的。

    这是GCC,没有优化:

    测试1.C:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    { 
      char *pointer[5];
    
    if(pointer[0] == NULL) {
      exit(1);
    }
    
    exit(0);
    
    }
    

    测试二:改变 pointer[0] == NULL !pointer[0]

    gcc-s测试1.c,gcc-s测试2.c,diff-u测试1.s测试2.s

        11
  •  -2
  •   ZeroCool    16 年前
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {   
      char pointer[5];  
      /* This is insense you are comparing a pointer to a value */   
      if(pointer[0] == NULL) {     
        exit(1);
      } 
      ...
    }
    
    =>           ...    
      movzbl    9(%ebp), %eax  # your code compares a 1 byte value to a signed 4 bytes one 
      movsbl    %al,%eax        # Will result in sign extension...
      testl  %eax, %eax      
                  ...
    

    注意,如果不是使用 -Wall 旗上 不过,您应该始终编译为优化的gcc代码。 顺便说一句,在变量前面加上volatile关键字,以避免gcc忽略它…

    请务必提及您的编译器内部版本:)