是的,使用 int 而不是 char 通常会产生显着的性能免费赠品。因此,C 语言使用 int 来尝试匹配处理器中寄存器的本机大小。
尽可能使用无符号整数是个好主意,并且仅在极少数/特定情况下,使用无符号整数以外的东西。除非你有充分的理由,否则避免使用小于 int 的东西。如果您尝试使用小于 int 的项目从编程习惯中获得一些免费的性能,您需要以另一种方式改变您的习惯。未签名也是如此,除非您有充分的理由使用已签名,否则请使用未签名的任何内容。
基本上反汇编(或编译为asm),看看你最喜欢的和其他编译器正在生成什么,注意chars引起的未对齐寻址,注意高位的掩码,signed chars的符号扩展等。这些是有时免费,有时不取决于该字节的来源和去向以及平台。还可以尝试至少 x86 和 arm,也许是 mips、gcc 3.x、4.x 和 llvm。特别注意单个字符如何与声明行中的整数列表混合可能导致后面的整数不对齐,从地址的角度来看这对于 x86 来说很好,但会降低性能(在 x86 上,即使使用缓存)。首先放置对齐的变量,然后最后放置未对齐的变量。其他不能或不喜欢不进行未对齐访问的平台将浪费额外的字节作为填充,因此您不一定会节省内存。过早的优化正在尝试调整到可变长度。使用简单的习惯,例如对所有内容都使用无符号整数,除非您有特定原因,将较大的、对齐的变量和结构放在声明列表的首位,未对齐的内容放在最后(短裤然后是字符)。
乘法(和除法)使这种习惯变得丑陋,避免代码中的乘法和除法是最好的习惯。如果您必须使用一个,请对其实现非常了解。例如,将两个字符相乘而不是两个整数要好得多(如果数字支持的话),所以如果你碰巧知道整数实际上是 7 位或 5 位或任何数量,请将它们向下键入以进行乘法并允许发生硬件乘法而不是软乘法。 (如果这些变量大小发生变化,可能是休眠错误!!)。尽管许多处理器都有硬件乘法器,但实际上很少能直接使用它。除非您帮助编译器,否则它必须进行库调用以检查溢出等,并且最终可能会执行软乘法,这非常昂贵。除法不好,因为大多数处理器不包括除法。如果他们这样做,您可能会落入同一个陷阱。乘以 N 位 * N 位变成 2*N 位的结果,这就是乘法问题出现的地方。除法时,数字保持不变或变小。在这两种情况下,isas 并不总是提供足够的位来覆盖溢出,并且需要一个库调用来解决处理器硬件限制。
浮点是一个类似的故事,只是要小心浮点。除非绝对必要,否则不要使用它。大多数人都不记得了
浮动一个;
浮动 b;
...
b = a * 1.0;
除非另有说明,否则 C 假定为双精度,因此上述乘法需要将 a 转换为双精度,然后相乘,然后将结果转换回单精度。有些 fpus 可以在同一条指令中以时钟为代价进行精度转换,有些则不能。精度转换是大多数浮点处理器错误存在(或确实存在)的地方。因此,要么对所有内容都使用双打,要么小心编码以避免这些陷阱:
浮动一个;
浮动 b;
...
b = a * 1.0F;
此外,大多数 isas 没有 FPU,因此避免浮点数学比避免定点乘法和除法更重要。假设大多数 fpus 都有错误。很难编写好的浮点代码(程序员经常因为不知道如何使用它并为其编写代码而丢掉了相当多的精度)。
一些简单的习惯和你的代码作为免费赠品运行起来明显更快、更干净。此外,编译器不必努力工作,因此您会遇到更少的编译器错误。
编辑添加浮点精度示例:
浮动乐趣1(浮动一个)
{
返回(a*7.1);
}
浮动乐趣2(浮动一个)
{
返回(a*7.1F);
}
第一个函数包含:
mulsd .LC0(%rip), %xmm0
使用 64 位浮点常量
.LC0
.long 1717986918
.long 1075603046
第二个函数包含所需的单精度乘法
mulss .LC1(%rip), %xmm0
具有单个精度常数
.LC1
.long 1088631603
char fun1 ( 字符 a )
{
返回(a+7);
}
int fun2 ( int a )
{
返回(a+7);
}
乐趣1:
添加 r0, r0, #7
和 r0, r0, #255
bx lr
乐趣2:
添加 r0, r0, #7
bx lr