目前我正在使用针对32位MIPS平台的代码库(C,C ++混合)。处理器是一个相当现代的处理器[只是提到我们有很好的处理能力和内存]。
代码库使用数据类型,如uint8 [1字节宽无符号整数],uint16 [2字节宽无符号整数],uint32 [4字节宽无符号整数]等。
我知道在将代码移植到不同平台时,这些构造的用法是如何有用的。
我的问题是:
使用uint16有什么用/有用,其中uint32也足够了(如果有的话)?
使用较短的数据类型(考虑数据对齐)是否可以节省内存使用量?
如果要节省几个字节的内存,在现代硬件中做些什么是明智的吗?
答案 0 :(得分:23)
使用uint16有什么用/有益,uint32也足够了(如果有的话)?
如果那些uint16s
是数组或结构的一部分,则可以节省内存,并且可能能够处理比那些相同数组或结构中的uint32s
更大的数据集。这真的取决于你的代码。
数据协议和文件格式可能会使用uint16s
,而使用uint32s
可能不正确。这取决于格式和语义(例如,如果您需要将值从65535回绕到0,uint16
将自动执行此操作,而uint32
则不会。)
OTOH,如果那些uint16s
只是单个局部或全局变量,用32位替换它们可能没有显着差异,因为它们可能由于对齐而占据相同的空间并且它们被传递为32无论如何,MIPS上的位参数(在堆栈或寄存器中)。
在使用较短的数据类型(考虑数据对齐)时,是否可以节省内存使用量?
可能会有节省,特别是当uint16s
是许多结构或大数组元素的一部分时。
如果要保存几个字节的内存,在现代硬件中这样做是否明智?
是的,你降低了内存带宽(这总是一件好事),并且当你操作较少的数据时,你经常会降低各种缓存未命中(数据缓存和TLB)。
答案 1 :(得分:9)
首先,如果您定义了uint16等类型,它们在哪里定义?它们不是标准类型,因此将在某些专有标题中定义 - 可能是您的或可能由某些第三方库提供;在这种情况下,您必须问自己该代码的可移植性,以及您是否正在创建在其他应用程序中可能没有意义的依赖项。
另一个问题是许多库(不明智的IMO)使用各种名称定义这样的类型,例如UINT16,uint16,U16 UI16等,它变得有点像确保类型协议和避免名称冲突的噩梦。如果定义了 这样的名称,理想情况下应将它们放在命名空间中,或者给定一个特定于库的前缀,以指示它们被定义用于哪个库,例如rtos::uint16
到{{1} }。
由于ISO C99标准库在stdint.h中提供了标准的位长特定类型,因此您应该优先使用它们在专有或第三方标头中定义的任何类型。这些类型具有rtos_uint16
后缀,例如_t
。在C ++中,它们可能被放置在uint16_t
命名空间中(尽管这不是给定的,因为在C99中引入了标头)。
1]使用uint16有什么用/有用uint32也足够了(如果有的话)?
除了我之前建议偏好std::
的{{1}}之外,至少有两个合理的理由使用长度特定类型:
2]在使用较短的数据类型(考虑数据对齐)时,是否可以节省内存使用量?
可能,但如果记忆不是你的问题,那不是使用它们的好理由。值得考虑的可能是大型数据对象或数组,但全球应用很少值得努力。
3]如果要保存几个字节的内存,在现代硬件中做些什么是合理的吗?
见[2]。 “现代硬件”但并不一定意味着大量资源;例如,有大量的32位ARM Cortex-M器件,只有几Kb的RAM。这更多是关于模具空间,成本和功耗,而不是设计或建筑时代。
答案 2 :(得分:3)
cstdint
有typedef
个加载用于不同目的。
intN_t
特定宽度int_fastN_t
表示最快的整数,至少有N位int_leastN_t
表示最小整数,至少有N位unsigned
当量您应该根据自己的情况选择。在std::vector
中存储数千并且没有进行大量计算? intN_t
可能是你的男人。需要快速计算少量整数? int_fastN_t
可能是你的家伙。
答案 3 :(得分:2)
答。 1.软件具有一定的要求和规范,严格说明在编码/解码或其他某些使用时仅占用参数的8/16位。因此,即使你将一个大于127的值分配到u8中,它也会自动为你修剪数据。
答。 2.我们不应该忘记我们的编译器超越智能来进行优化,无论是内存还是复杂性。因此,建议尽可能使用较小的内存。
答。 3.当然,在现代h / w中保存记忆是有意义的。
答案 4 :(得分:2)
必须检查生成的机器代码/汇编程序以验证是否有任何代码保存。在RISC类型架构中,典型的立即数是16位,但是使用uint16_t无论如何都会消耗一个完整的32位寄存器 - 因此,如果使用int类型,但是提交使用接近零的值将产生相同的结果并且更加可移植。
在现代平台中,IMO节省内存也是值得的。更严格的代码导致例如更好的电池寿命和更流畅的用户体验。但是,我建议只在使用(大型)数组时,或者当变量映射到某个真实的HW资源时,才能对大小进行微管理。
PS。编译器很聪明,但编写它们的人现在可以使它们变得更好。
答案 5 :(得分:1)
使用uint16_t
代替uint32_t
可以节省内存。它也可能是硬件约束(例如,某些外设控制器实际上发送的是16位!)但是,它可能不值得使用它,因为缓存和对齐考虑因素(你真的需要进行基准测试)。
答案 6 :(得分:1)
使用uint16有什么用/有益,uint32也足够了(如果有的话)?
有些unsigned char
是16位值的CPU。如果不使用typedef,单元测试这样的代码会很困难(uint16只是适当类型的typedef)。
此外,通过使用这些typedef,可以更轻松地在不同平台上构建而不会出现太多问题。
在使用较短的数据类型(考虑数据对齐)时,是否可以节省内存使用量?
不,这不是重点。如果uint16
是unsigned short
的typedef,那么您可以在任何地方使用unsigned short
,但在不同的平台上可能会使用不同的类型。
当然,使用较小的类型会减少内存消耗。例如,使用uint16而不是uint32,但仅限于使用数组。
如果要保存几个字节的内存,在现代硬件中这样做是否明智?
这取决于平台:
答案 7 :(得分:1)
您的问题的答案归结为一个关键概念:数据有多大?如果你正在处理很多,那么使用较小数据类型的好处是显而易见的。可以这样想:只需计算新发现的最大已知质数,就可以在典型的工作站上耗尽内存。这个数字本身需要超过一千兆字节才能存储。这并不包括计算实际数量。如果您使用的是厚数据类型而不是瘦数据类型,则可能需要使用两千兆字节。一个简单的例子,但仍然是一个好的例子。
答案 8 :(得分:1)
使用int32_t
和朋友之类的精确宽度整数类型有助于避免int
和long
具有不同大小的平台之间的符号扩展错误。例如,当应用位掩码或位移时,这些可能发生。例如,如果您在long
上执行这些操作,并且您的代码适用于32位long
,那么对于64位long
,它可能会中断。另一方面,如果您使用uint32_t
,则无论平台如何,您都可以确切知道结果。
它们对于在平台之间交换二进制数据也很有用,您只需要担心存储数据的字节顺序而不是位宽;如果你在文件中写int64_t
,你知道在另一个平台上你可以阅读它并将其存储到int64_t
中。如果您在一个平台上写出long
而不是64位,则最终可能需要在另一个平台上使用long long
,因为long
只有32位。
保存内存通常不是原因,除非您谈论的是非常有限的环境(嵌入式内容)或大型数据集(例如包含5000万个元素的数组)。