我怀疑基于短的代码应该以任何重要的方式变得更慢和更大的说法(假设这里是局部变量,没有关于shorts 在适当情况下肯定会得到回报的大型数组的争议),所以我尝试了在我的Intel(R) Core(TM) i5 CPU M 430 @ 2.27GHz 上做基准测试
我用过(long.c):
long long_f(long A, long B)
{
//made up func w/ a couple of integer ops
//to offset func-call overhead
long r=0;
for(long i=0;i<10;i++){
A=3*A*A;
B=4*B*B*B;
r=A+B;
}
return r;
}
在基于long、int 和short 的版本(%s/long/TYPE/g) 中,使用-O3 和-Os 中的gcc 和clang 构建程序并测量大小和运行时间每个函数的 1 亿次调用。
f.h:
#pragma once
int int_f(int A, int B);
short short_f(short A, short B);
long long_f(long A, long B);
main.c:
#include "f.h"
#include <stdlib.h>
#include <stdio.h>
#define CNT 100000000
int main(int C, char **V)
{
int choose = atoi(V[1]?:"0");
switch(choose){
case 0:
puts("short");
for(int i=0; i<CNT;i++)
short_f(1,2);
break;
case 1:
puts("int");
for(int i=0; i<CNT;i++)
int_f(1,2);
break;
default:
puts("long");
for(int i=0; i<CNT;i++)
long_f(1,2);
}
}
构建:
#!/bin/sh -eu
time(){ command time -o /dev/stdout "$@"; }
for cc in gcc clang; do
$cc -Os short.c -c
$cc -Os int.c -c
$cc -Os long.c -c
size short.o int.o long.o
$cc main.c short.o int.o long.o
echo $cc -Os
time ./a.out 2
time ./a.out 1
time ./a.out 0
$cc -O3 short.c -c
$cc -O3 int.c -c
$cc -O3 long.c -c
size short.o int.o long.o
$cc main.c short.o int.o long.o
echo $cc -O3
time ./a.out 2
time ./a.out 1
time ./a.out 0
done
我做了两次,结果似乎很稳定。
text data bss dec hex filename
79 0 0 79 4f short.o
80 0 0 80 50 int.o
87 0 0 87 57 long.o
gcc -Os
long
3.85user 0.00system 0:03.85elapsed 99%CPU (0avgtext+0avgdata 1272maxresident)k
0inputs+0outputs (0major+73minor)pagefaults 0swaps
int
4.78user 0.00system 0:04.78elapsed 99%CPU (0avgtext+0avgdata 1220maxresident)k
0inputs+0outputs (0major+74minor)pagefaults 0swaps
short
3.36user 0.00system 0:03.36elapsed 99%CPU (0avgtext+0avgdata 1328maxresident)k
0inputs+0outputs (0major+74minor)pagefaults 0swaps
text data bss dec hex filename
137 0 0 137 89 short.o
109 0 0 109 6d int.o
292 0 0 292 124 long.o
gcc -O3
long
3.90user 0.00system 0:03.90elapsed 99%CPU (0avgtext+0avgdata 1220maxresident)k
0inputs+0outputs (0major+74minor)pagefaults 0swaps
int
1.22user 0.00system 0:01.22elapsed 99%CPU (0avgtext+0avgdata 1260maxresident)k
0inputs+0outputs (0major+73minor)pagefaults 0swaps
short
1.62user 0.00system 0:01.62elapsed 99%CPU (0avgtext+0avgdata 1228maxresident)k
0inputs+0outputs (0major+73minor)pagefaults 0swaps
text data bss dec hex filename
83 0 0 83 53 short.o
79 0 0 79 4f int.o
88 0 0 88 58 long.o
clang -Os
long
3.33user 0.00system 0:03.33elapsed 99%CPU (0avgtext+0avgdata 1316maxresident)k
0inputs+0outputs (0major+71minor)pagefaults 0swaps
int
3.02user 0.00system 0:03.03elapsed 99%CPU (0avgtext+0avgdata 1316maxresident)k
0inputs+0outputs (0major+71minor)pagefaults 0swaps
short
5.27user 0.00system 0:05.28elapsed 99%CPU (0avgtext+0avgdata 1236maxresident)k
0inputs+0outputs (0major+69minor)pagefaults 0swaps
text data bss dec hex filename
110 0 0 110 6e short.o
219 0 0 219 db int.o
279 0 0 279 117 long.o
clang -O3
long
3.57user 0.00system 0:03.57elapsed 99%CPU (0avgtext+0avgdata 1228maxresident)k
0inputs+0outputs (0major+69minor)pagefaults 0swaps
int
2.86user 0.00system 0:02.87elapsed 99%CPU (0avgtext+0avgdata 1228maxresident)k
0inputs+0outputs (0major+68minor)pagefaults 0swaps
short
1.38user 0.00system 0:01.38elapsed 99%CPU (0avgtext+0avgdata 1204maxresident)k
0inputs+0outputs (0major+70minor)pagefaults 0swaps
结果相当接近,但随着编译器和编译器设置的不同,它们相对差异很大。
我的结论是,在函数体或签名中选择 int 和 shorts(数组是一个不同的问题),因为一个应该比另一个执行得更好或生成更密集的代码大多是徒劳的(至少在代码中)不固定到具有特定设置的特定编译器)。两者都很快,所以我会选择更适合我的程序语义或更好地传达我的 API 的类型
(如果我期望一个短的正值,不妨在签名中使用 uchar 或 ushort。)
C 程序员倾向于使用ints,因为 C 在历史上一直偏爱它们(整数文字往往是 ints,促销往往是 ints,曾经有隐含的 int 规则用于声明和未声明函数等)和ints 应该非常适合该架构,但归根结底,具有可读、可维护源代码的密集、高性能机器代码才是最重要的,如果你的理论做某事在源代码中至少没有明显有助于实现这些目标中的一个,我认为这是一个糟糕的理论。