【问题标题】:On a 16-bit microprocessor, should I be using datatype short instead of int?在 16 位微处理器上,我应该使用数据类型 short 而不是 int 吗?
【发布时间】:2011-06-27 04:01:17
【问题描述】:

我读过使用shortint 实际上会导致编译器效率低下,因为它需要使用int 数据类型,而不管由于C 整数提升。对 16 位微处理器来说是这样吗?

另一个问题:如果我有一个 1 和 0 的数组,在这个 16 位微处理器中使用 uint8_tunsigned char 是最有效的吗?还是将其转换回int仍然存在问题..

请帮我清理一下我脑海中的这个泥泞问题。谢谢!

【问题讨论】:

  • 您还没有告诉我们您在谈论什么特定的 16 位微处理器。至少有几十个潜在的候选人,为什么不告诉我们是谁制造的,它的型号是什么。
  • 整数类型的确切大小是实现定义的——编译器可以根据目标平台来决定。我怀疑使用处理器本身不支持的int 的大小是否足够愚蠢——尤其是因为int 被非正式地认为是目标的本机字长。在有问题的目标上检查有问题的编译器上的sizeof int
  • @jer:如果有帮助的话,我正在开发 Analog Device Blackfin。
  • sizeof(int),我得到4。使用sizeof(short),我得到2。我有点希望sizeof(int)也是2...我还应该使用int吗?对我来说仍然没有完全的意义。谢谢。
  • 不要将 C 实现与微处理器混淆。前者可以使其类型几乎任意大小,即使 CPU 本身无法处理它。

标签: c types char int short


【解决方案1】:
  1. 真的有问题吗?在我听说过的大多数 16 位系统上,intshort 最终大小相同(16 位),因此实际上应该没有区别。

  2. 如果系统上存在uint8_t,它将成为unsigned char 的同义词。 unsigned char 将是系统上可用的最小无符号类型。如果超过 8 位,则不会有 uint8_t。如果小于 8 位,则违反标准。不会有效率差异,因为必须根据另一个来定义一个。

最后,您真的需要担心这些微观差异吗?如果您这样做,您需要查看程序集输出或(更有可能)配置文件,看看哪个更快。

【讨论】:

    【解决方案2】:

    在 Blackfin 上,32 位还是 16 位类型通常会产生更高的性能可能不是一个简单的答案,因为它支持 16、32 和 64 位指令,并且有两个 16 位 MAC。这将取决于操作,但我建议您相信您的编译器优化器会做出这样的决定,它比您可能关心的更了解处理器的指令时序和调度。

    也就是说,在您的编译器中,int 和 short 在任何情况下都可能是相同的大小。请参阅文档,使用 sizeof 进行测试,或查看 limits.h 标头中的数字范围,以推断宽度或各种类型。

    如果您确实想限制数据类型大小,请使用stdint.h 类型,例如int16_t

    stdint.h 还定义了fastest minimum-width integer types 例如int_fast16_t,这将保证最小宽度,但如果它在您的目标上更快,则会使用更大的类型。这可能是解决您的问题的最便携的方法,但它依赖于实现者对要使用的适当类型做出正确的决定。在大多数架构上它几乎没有区别,但在 RISC 和 DSP 架构上可能并非如此。也可能不是特定尺寸在所有情况下都是最快的,在 Blackfin 的情况下可能尤其如此。

    在某些情况下(大量数据从外部存储器传输到存储器),最快的大小可能是与数据总线宽度相匹配的大小。

    【讨论】:

      【解决方案3】:

      在 16 位或更大的处理器上,如果您不在乎会占用多少存储空间,请使用“int”而不是“short”或“signed char”。如果您不关心存储要求或包装行为,请使用“unsigned int”而不是“unsigned short”或“unsigned char”。在 8 位处理器上,“char”类型可能比“int”快,但在 16 位和更大的处理器上,16 位数学比 32 位数学快,“int”可能是 16 位,所以无需使用“short”或“char”来提高速度。

      顺便说一句,在某些处理器上,'unsigned short' 比 'unsigned int' 慢得多,因为 C 标准要求对无符号类型 'wrap' 的操作。如果无符号短变量“foo”存储在寄存器中,典型的 ARM 编译器会为“foo+=1;”生成代码将生成一条指令来执行增量,两条指令将值截断为 65535 [顺便说一句,注意到“foo”永远不会超过 65536 的优化编译器可以削减一条指令,但我不知道是否有任何真正的编译器会]。签名的“short”不必比“signed int”慢,因为标准不强制要求截断;不过,我不确定是否有任何编译器会跳过有符号类型的截断。

      【讨论】:

      • IMO 你关于 unsigned 的讨论没有意义。您可以只使用完整寄存器进行加法、减法、乘法运算,并且仅在需要存储结果时才对 65535 进行屏蔽(这是模运算的一个很好的属性)。实际上shortchar 只是“存储”类型,因为它们会在表达式中自动转换为int...例如unsigned char x=255; int y = x+1;' will assign 256 to y`,即使char 是8 位而int 是16,因为在添加过程中不会发生包装。
      • 有点混淆了换行和截断;她们不一样。我刚刚在 ARM7TDMI 目标上使用 ARM 模式(而不是 Thumb)检查了 ARM 编译器(ARM 自己的 armcc)的输出,您的断言不成立。
      • @6502:如果一个无符号短变量保存在寄存器中,那么符合规范将要求将寄存器截断为无符号短。说“intval = ushortval + 1;”将要求该值不被截断,但“ushortval +=1; intval = ushortval;”需要截断,就像“if (!++ushortval) ...”一样。
      • @Clifford:你尝试了什么,结果如何?请注意,寄存器中的中间计算不必被截断为 ushort(实际上它们在任何情况下都不重要),但是如果未签名,则必须截断对恰好已优化到寄存器的变量的赋值。签名寄存器不必被截断,但如果某些编译器仍然这样做,我不会感到惊讶。
      • @supercat:我的尝试和结果不容易在评论区报告。我声明了一个 volatile short 整数变量,然后按照您的建议执行 foo+=1,然后将其分配给第二个静态 volatile short。我使用签名短裤,因为您没有指定,并且在任何情况下都指定了原始帖子。它们是易失的,以防止编译器对存储的值做出假设。静态声明是强制内存存储而不是寄存器。我可能不在乎进一步调查。
      【解决方案4】:

      我强调在依赖字节大小的项目中使用如下所示的块:

      typedef uint8 char
      typedef uint16 short
      typedef uint32 long
      

      适用于任何数据类型。

      任何转换问题都应该在编译时解决。这些将取决于 cpu 和编译器。

      当然,在 16 位 CPU 上添加 2 个 32 位数字将需要编译器进行一些处理。当你从内存加载时也会有一些有趣的事情,这取决于内存字宽以及是否可以从任何地址加载,或者是否必须从给定边界加载字节

      short,YMMV,并在profiling后优化。

      【讨论】:

      • 无需滚动您自己的数据类型,只需 #include <stdint.h> 即可获得 uint8_tuint32_t 等。这样,您就不必为每个平台编写自己的 typedef,就像那些数据类型(由 C99 标准)定义为所有符合实现的指定长度。
      • @bta:当然,如果您可以依赖使用符合 C99 的编译器!但是,是的,如果可以的话,这是一个“最佳实践”。
      • 只是一个头文件实现,不需要 C99 编译器;您可以创建自己的 C99 兼容任何不提供它的编译器。这将使您不必为您可能使用过的所有编译器创建这些类型。
      猜你喜欢
      • 1970-01-01
      • 2011-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      相关资源
      最近更新 更多