int16 的嵌入式 C 编译大小比 int32 大。为什么?
Embedded C compile size is bigger with int16's than with int32's. Why?
我正在为 Freescale Coldfire 处理器开发嵌入式 C 固件。在编写了一些代码之后,我开始寻找减少构建大小的方法。我们的名额有限 space,所以这对我来说很重要。
我意识到我的代码中有几个 int32,但我只需要 int16。为了保存 space 我尝试用 int16 替换相关变量。当我构建它时,构建的大小增加了大约 60 个字节。
我认为这可能是我的结构是如何打包的,所以我定义了我想要的打包方式,但它没有改变。
#pragma pack(push, 1)
// Struct here
#pragma pack(pop)
我可以看到它保持不变,但我不知道是什么导致它上升。这里有什么想法吗?可能是什么原因造成的?
编辑:
是的,看起来它只是生成额外的指令来说明 32 位是处理器的优化大小。我应该先检查数据表。
这是正在生成的额外程序集:
0x00000028 0x3210 move.w (a0),d1
0x0000002A 0x48C1 ext.l d1
; Other instructions between
0x0000002E 0x3028000E move.w 14(a0),d0
0x00000032 0x48C0 ext.l d0**
您的编译器可能会发出 int32 的代码,这很好;它可能是您的架构的自然 int 大小(这是真的吗?是 sizeof(int)==4 吗?)。
我猜测大小增加来自三个地方:
进行对齐工作
32 位整数可能在堆栈和其他地方自然对齐,
所以通常不必发出代码来确保“
堆栈是 4 字节对齐的”。如果你在其中撒上一堆 16 位整数
您的代码,它可能必须添加填充(额外添加到帧指针
作为修复?)通常一个添加指令涵盖 frame/stack
维护,但可能会发出额外的说明以保证
对齐.
在 16 位和 32 位整数之间转换
对于 32 位整数,大多数指令自然有效。对于较小的整数,有时编译器必须发出 chops/slices 向上位的代码,以便
它保留了较小的语义。 (也许做一个额外的 AND 指令来屏蔽
关闭一些高位或 OR 指令来设置一些位)。
来回记忆
标准 LOADS 和 STORES 用于 32 位整数(这可能是您机器的自然大小)。有可能,当它必须存储 仅 2 个字节 而不是 4 个时,架构必须发出额外的指令来存储非标准 int(通过切碎 int,使用具有较长编码的奇怪指令,或使用位指令来分割指令)。
这些都是猜测。最好的办法就是看汇编代码,看看是怎么回事!
To save space I tried replacing the relevant variables with int16's.
When I built it, the size of the build went up by about 60 bytes.
这对我来说意义不大。使用较小的数据类型不一定会转换为较少的指令。当 运行 软件但不一定构建大小时,它可以减少内存使用。
因此,例如,此处使用较小数据类型可能会增加二进制文件大小的原因可能是因为使用较小类型需要更多指令或更长指令。例如,对于 non-word/dword 对齐的内存,编译器可能必须使用更多指令来进行未对齐的移动。如果所有通用寄存器都较大,则可能必须使用特殊指令来提取 lower/upper 个单词。在这种情况下,除了使用那些较小的类型增加二进制大小之外,您的性能也可能会受到轻微影响(但当代码为 运行 时使用的内存更少)。
可能有多种情况,它特定于您使用的确切编译器和体系结构(汇编代码将揭示确切原因),但简而言之,使用较小的变量类型并不一定意味着较小的变量-sized builds/fewer 指令,并且很容易表示相反的意思。
我正在为 Freescale Coldfire 处理器开发嵌入式 C 固件。在编写了一些代码之后,我开始寻找减少构建大小的方法。我们的名额有限 space,所以这对我来说很重要。
我意识到我的代码中有几个 int32,但我只需要 int16。为了保存 space 我尝试用 int16 替换相关变量。当我构建它时,构建的大小增加了大约 60 个字节。
我认为这可能是我的结构是如何打包的,所以我定义了我想要的打包方式,但它没有改变。
#pragma pack(push, 1)
// Struct here
#pragma pack(pop)
我可以看到它保持不变,但我不知道是什么导致它上升。这里有什么想法吗?可能是什么原因造成的?
编辑:
是的,看起来它只是生成额外的指令来说明 32 位是处理器的优化大小。我应该先检查数据表。
这是正在生成的额外程序集:
0x00000028 0x3210 move.w (a0),d1
0x0000002A 0x48C1 ext.l d1
; Other instructions between
0x0000002E 0x3028000E move.w 14(a0),d0
0x00000032 0x48C0 ext.l d0**
您的编译器可能会发出 int32 的代码,这很好;它可能是您的架构的自然 int 大小(这是真的吗?是 sizeof(int)==4 吗?)。 我猜测大小增加来自三个地方:
进行对齐工作
32 位整数可能在堆栈和其他地方自然对齐, 所以通常不必发出代码来确保“ 堆栈是 4 字节对齐的”。如果你在其中撒上一堆 16 位整数 您的代码,它可能必须添加填充(额外添加到帧指针 作为修复?)通常一个添加指令涵盖 frame/stack 维护,但可能会发出额外的说明以保证 对齐.
在 16 位和 32 位整数之间转换
对于 32 位整数,大多数指令自然有效。对于较小的整数,有时编译器必须发出 chops/slices 向上位的代码,以便 它保留了较小的语义。 (也许做一个额外的 AND 指令来屏蔽 关闭一些高位或 OR 指令来设置一些位)。
来回记忆
标准 LOADS 和 STORES 用于 32 位整数(这可能是您机器的自然大小)。有可能,当它必须存储 仅 2 个字节 而不是 4 个时,架构必须发出额外的指令来存储非标准 int(通过切碎 int,使用具有较长编码的奇怪指令,或使用位指令来分割指令)。
这些都是猜测。最好的办法就是看汇编代码,看看是怎么回事!
To save space I tried replacing the relevant variables with int16's. When I built it, the size of the build went up by about 60 bytes.
这对我来说意义不大。使用较小的数据类型不一定会转换为较少的指令。当 运行 软件但不一定构建大小时,它可以减少内存使用。
因此,例如,此处使用较小数据类型可能会增加二进制文件大小的原因可能是因为使用较小类型需要更多指令或更长指令。例如,对于 non-word/dword 对齐的内存,编译器可能必须使用更多指令来进行未对齐的移动。如果所有通用寄存器都较大,则可能必须使用特殊指令来提取 lower/upper 个单词。在这种情况下,除了使用那些较小的类型增加二进制大小之外,您的性能也可能会受到轻微影响(但当代码为 运行 时使用的内存更少)。
可能有多种情况,它特定于您使用的确切编译器和体系结构(汇编代码将揭示确切原因),但简而言之,使用较小的变量类型并不一定意味着较小的变量-sized builds/fewer 指令,并且很容易表示相反的意思。