使用 Int(32 位)而不是字符(8 位)来"帮助"处理器



在C中,我们经常使用char来表示小数字。然而,处理器总是使用Int(或32位)值从寄存器中读取(或从寄存器中提取)。因此,每次我们需要在程序处理器中使用char或8位时,都需要从regsiter中获取32位,并从中"解析"8位。因此,如果内存不是限制,那么更频繁地使用Int代替char有意义吗?它会"帮助"处理器吗?

有编译器部分和cpu部分。

如果你告诉编译器你使用的是char而不是int,在静态分析过程中,它会知道变量的边界在0-255之间,而不是0-(2^32-1)。这将使它能够更好地优化您的程序。

在cpu方面,您的假设并不总是正确的。以x86为例,它有用于32位和8位寄存器访问的寄存器eaxal。如果只想使用字符,那么使用al就足够了。没有性能损失。

我做了一些简单的基准测试来回应以下评论:

al:

format PE GUI 4.0
xor ecx, ecx
dec ecx
loop_start:
inc al
add al, al
dec al
dec al
loopd short loop_start
ret

eax:

format PE GUI 4.0
xor ecx, ecx
dec ecx
loop_start:
inc eax
add eax, eax
dec eax
dec eax
loopd short loop_start
ret

次数:

$ time ./test_al.exe 
./test_al.exe  0.01s user 0.00s system 0% cpu 7.102 total
$ time ./test_eax.exe 
./test_eax.exe  0.01s user 0.01s system 0% cpu 7.120 total

所以在这种情况下,al稍微快一点,但有时eax出来得更快。差别真的可以忽略不计。但是cpu并不是那么简单,可能会出现代码对齐问题、缓存和其他问题,所以最好对自己的代码进行基准测试,看看是否有任何性能改进。但是imo,如果你的代码不是非常紧凑,最好相信编译器会优化。

如果我是你的话,我会坚持使用int,因为这可能是你的平台最原生的积分类型。在内部,您可能期望将较短的类型转换为int,这样实际上会降低性能。

您应该永远不要使用char,并期望它在各个平台之间保持一致。尽管C标准将sizeof(char)定义为1,但char本身可以是signedunsigned。选择取决于编译器。

如果您认为使用8位类型可以获得一些性能增益,那么请明确使用signed charunsigned char

来自ARM系统开发人员的指南

"大多数ARM数据处理操作仅为32位。因此,您应该使用一个32位的数据类型,int或long,尽可能用于局部变量。避免使用char和简称为局部变量类型,即使您正在操作一个8或16位值"

书中的一个示例代码来证明这一点。注意char的环绕处理,而不是无符号的int。

int checksum_v1(int *data)
{
char i;
int sum = 0;
for (i = 0; i < 64; i++)
{
sum += data[i];
}
return sum;
}

使用i作为字符时的ARM7程序集

checksum_v1
MOV r2,r0 ; r2 = data
MOV r0,#0 ; sum = 0
MOV r1,#0 ; i = 0
checksum_v1_loop
LDR r3,[r2,r1,LSL #2] ; r3 = data[i]
ADD r1,r1,#1 ; r1 = i+1
AND r1,r1,#0xff ; i = (char)r1
CMP r1,#0x40 ; compare i, 64
ADD r0,r3,r0 ; sum += r3
BCC checksum_v1_loop ; if (i<64) loop
MOV pc,r14 ; return sum

当i是无符号整数时的ARM7程序集

checksum_v2
MOV r2,r0 ; r2 = data
MOV r0,#0 ; sum = 0
MOV r1,#0 ; i = 0
checksum_v2_loop
LDR r3,[r2,r1,LSL #2] ; r3 = data[i]
ADD r1,r1,#1 ; r1++
CMP r1,#0x40 ; compare i, 64
ADD r0,r3,r0 ; sum += r3
BCC checksum_v2_loop ; if (i<64) goto loop
MOV pc,r14 ; return sum

如果你的程序足够简单,优化器可以做正确的事情而不必担心。在这种情况下,普通的int将是最简单的(并且是前向的)解决方案。

但是,如果您真的想将特定的位宽和速度结合起来,可以使用C99标准中的7.18.1.3最快的最小宽度整数类型(需要符合C99的编译器)。

例如:

int_fast8_t x;
uint_fast8_t y;

是有符号和无符号类型,保证能够存储至少8位数据,并使用通常更快的底层类型。当然,这完全取决于你之后对数据做了什么。

例如,在我测试过的所有系统上(参见:C++中的标准类型大小),快速类型都是8位长。

最新更新