C语言非常灵活且富有表现力。这就是为什么它成功并具有被“更好”的语言取代的弹性的一些原因。其灵活性的一个例子是可以用功能上等效的多种方式来编写表达式。这样可以使编码样式适应个人需要。但是,有一个陷阱:有时,等效的代码有时会有细微的差别。这可能发生在最简单的代码中,我们将在本文中探讨一些可能性。
C通常提供几种不同的方法来做某事,所有这些方法都是完全等效的。例如,假设x是一个普通的int变量,则以下每个语句将执行完全相同的工作:
x = x + 1;
x + = 1;
x ++;
++ x;
在每种情况下,x将加1。唯一可能的区别是,能力较差的编译器可能会为后两个选项生成稍微更好的代码(这暗示着获得更好的编译器是值得的)。
以这种方式使用的两种形式的++运算符产生相同的结果。但是,如果使用表达式的值,则前增量和后增量是不同的,因此:
y = x ++; // y在增量之前具有x的值
y = ++ x; // y的增量为x
有趣的是,由于需要分配存储空间以保持x的旧值,因此后增量稍微“贵”些。但是,编译器可能会对此进行优化。如果在不使用表达式值的情况下分配了存储空间,则肯定需要新的编译器!
如果,代替作为一个INT,X是一个指针INT,加法1将具有增加的效果4(32位机器上)。如果这让您大吃一惊,那么有必要对指针算法进行一些梳理。
但是,有时看似等效的构造有非常细微的差异……
在任何一种编程语言中,最简单的事情可能就是为变量分配一个值。因此,在C语言中,我们可以这样写:
阿尔法= 99;
Beta = 99;
伽玛= 99;
当然,可以这样写得更紧凑:
alpha = beta =伽马= 99;
这些都是100%等效的。还是他们?
在大多数情况下,这两种构造是完全等效的,但是(至少)在四种情况下选择其中一种可能会有所不同:
首先,在大多数情况下,每个变量都是独立的,也许有一条注释说明为什么将其设置为该值可能是适当的。
其次,编写可维护的代码总是好的。也许在将来的某个时候,可能需要更改代码,以使所有三个变量都不会设置为相同的值。第一种格式更易于修改。
第三个原因与不合标准的编译器有关,后者可能会为第一个构造生成如下代码:
mov r0,#99
mov alpha,r0
mov r0,#99
mov beta,r0
mov r0,#99
movγ,r0
第二种结构提示r0只需要加载一次。同样,更好的编译器将不需要提示。
最后,还有执行顺序的问题。在第一种构造中,完全清楚的是,将首先分配alpha,最后分配gamma。编译器将这样解释第二个构造:
alpha =(beta =(gamma = 99));
这意味着分配顺序相反。但这有关系吗?大多数时候,它不是。但是,如果这些是设备寄存器,而不是普通变量,则可能会有很大的不同。硬件需要以精确的顺序加载设置值是很常见的。
因此,我要说的是,应避免在一个语句构造中进行多个分配。
总体而言,尽管C是一门小语言,但可以说通过减少操作方式,它甚至可以变得更小。结果可能是更清晰,更可维护的代码。