有效地将 16 位 short 转换为 8 位 char
Posted
技术标签:
【中文标题】有效地将 16 位 short 转换为 8 位 char【英文标题】:Efficiently converting 16-bits short to 8-bits char 【发布时间】:2013-02-03 16:46:36 【问题描述】:我正在研究一个没有硬件划分的 Cortex M0 cpu,所以每次我划分一些东西时,都会使用 GCC 库函数。现在我最常做的除法之一是除以 256,将短裤转换为字节。有没有什么方法可以比默认的 GCC 库更有效地做到这一点(例如通过位移)?
【问题讨论】:
运算符 '>>' 会为您解决问题吗?你知道'>> 8'吗? 你不是说除以256吗?不是 255? 您可能会对 Hacker's 的乐趣一书的第 10 章“整数除以常数”感兴趣。但是 GCC 的实现者可能已经阅读了它。在假设有更好的方法之前,您是否查看了程序集? (注意:此评论假定您确实是指 255) 如果你除以 255 得到高位 8 位,我有一个坏消息要告诉你。 @JanDvorak 不,它必须是 256,你是对的。 【参考方案1】:根据您的 cmets,您希望 -32768 映射到 0,而 32767 映射到 255。因此,您想要的公式是:
short s = /* input value */;
unsigned char c = (unsigned char) ((s + 32768) / 256);
其他评论者指出,您可以通过右移或其他各种策略来除以 256,这是正确的 - 一个合理的版本是:
unsigned char c = (unsigned char) ((s + 32768) >> 8);
但是,没有必要进行此类优化。 GCC 非常聪明地将除以常数操作转换为特殊情况的实现,在这种情况下,它会将这两者编译成完全相同的代码(使用 -O2 -mcpu=cortex-m0 -mthumb
和 GCC 4.7.2 进行测试):
mov r3, #128
lsl r3, r3, #8
add r0, r0, r3
lsr r0, r0, #8
uxtb r0, r0
如果您尝试太聪明(就像其他答案中的联合或指针转换示例一样),您可能会混淆它并得到更糟糕的结果 - 特别是因为那些通过内存负载工作,并且添加 32768 意味着你已经在寄存器中有值了。
【讨论】:
你会感到惊讶...我曾经看到一个 GCC 端口,它通过发出乘法操作码来处理 C 代码中的显式移位操作 - 有人可能假设了一个硬件乘法器,因此成本相当,尽管它试图运行的实际实验硬件没有实现乘法指令。幸运的是,作为 FPGA,它很容易添加。希望分裂的情况得到更好的处理。 @ChrisStratton:是的——这就是为什么经常阅读生成的程序集很有用,只是为了确保您认为正在发生的事情实际上正在发生!尽管您描述的案例很明显是 GCC 中的一个错误。【参考方案2】:只需投射一个指针。
unsigned char *bytes = (unsigned char*)&yourvalue;
现在,bytes[0]
将保存一个字节的值,bytes[1]
将保存另一个。
顺序取决于系统的字节顺序
【讨论】:
@JanDvorak 是的,但答案声明结果取决于字节序。所以这绝不是不正确的。此外,OP 确切地知道他正在为哪种架构开发,所以他事先知道字节顺序。 当独立于平台的代码更干净并且可能更快时,编写平台相关代码的理由几乎没有 - 程序不一定将其整个生命周期都花在最初编写的目标上。在移位情况下,优化编译器将变量保存在寄存器(而不是内存)中的可能性很高;在指针的情况下,可能有一些优化编译器足够聪明,可以确定这是您使用指针并使用寄存器实现的唯一原因,但似乎不太可能。【参考方案3】:你可以这样使用union
:
#include <stdio.h>
union Word
struct
unsigned char high;
unsigned char low;
byte;
unsigned short word;
;
int main(int argc, char **argv)
union Word word;
word.word = 0x1122;
printf("L = 0x%x, H = 0x%x", word.byte.low, word.byte.high);
return 0;
【讨论】:
使用联合与位移是否会提高性能?似乎联合会更快,因为不需要额外的操作,但也许它有其他开销? @Joshua 在汇编级别使用union
只不过是mov
指令。
这将给出错误的答案,因为它假定一个大端处理器,但所讨论的目标实际上是小端。您可以修复它,但仍然存在出错的风险,尤其是当代码被移植到其他地方时。以上是关于有效地将 16 位 short 转换为 8 位 char的主要内容,如果未能解决你的问题,请参考以下文章