作为低范围数值类型的char?

3

在使用C语言编程时,有时我的函数会接收0到4范围内的数字值。一个32位的int可以容纳多达2,147,483,647个值。这是我没有使用的大量分配的内存。我了解到的最低范围类型是char(它可以保存从0255的值,对吗?)。将低范围的数值存储在char中是一个好的实践吗?还有其他的数据类型可以使用吗?


你认为多少内存才算是“很多”? - hookenz
只有在需要分配大量内存时,这才是一个真正的问题!如果你正在谈论函数参数传递,4个字节与1个字节相比并不重要,即使你传递了100个参数。 - hookenz
1
char 有2 ** CHAR_BIT个值,最少256个,但它可以是signedunsigned。因此,你的范围是错误的。不过对于这么低的无符号数来说,这并不重要。 - Deduplicator
另外,您是指0-4(需要3位)还是0-3(只需要2位),虽然在整个计划中这并不重要。 - Foon
7个回答

4
如果您确实需要节省空间,可以使用位域。但请注意,访问数据可能需要更多的时间周期。(即使在现代硬件上访问char类型也可能比本机整数大小需要更多的时间周期)
(编辑以提供示例:)
struct packed_values
{
     unsigned int val1       : 3; /* ranges from 0-7 */
     unsigned int val2       : 3;
     unsigned int val3       : 3; 
     unsigned int val4       : 3;
     unsigned int val5       : 3;
     unsigned int val6       : 3;
     unsigned int val7       : 3;
     unsigned int val8       : 3;
     unsigned int val9       : 3;
     unsigned int val10      : 3;
     unsigned int padding    : 2; // make this be 32bits
};

packed_value myval;
myval.val1 = 5;
myval.val2 = 6;
myval.val3 = 7;

)


谢谢你的回答!我也想接受这个答案,但我只能做一次 :-). +1 - cdonts

4
如果函数参数是标量,实际上传递给函数时它肯定会被提升为至少32位类型,因此使用 char 没有任何实际区别。我认为更重要的是可读性,而 int 是显而易见的“一般整数值”类型。
然而,如果您可能有一个相当大的值数组,使用 char 将使这些值在内存中更紧密地打包。 如果您的内存非常紧张,可以仅使用3或4位每个值来更紧密地打包它们(3是最小值,4对齐更好)。 但这将肯定不够高效。

请记住,char 的实现定义了有符号性。 - Deduplicator
1
此外,原帖作者从未提到他使用的是现代桌面系统。也许他正在使用微控制器板... - Deduplicator
每个答案都带有一些假设,@Deduplicator。如果他们不正确,我相信OP会发表评论的。如果平台是意外的,标记自己的问题也是明智的。 - Matti Virkkunen
1
那么,你认为所有东西都是桌面吗?其实并不需要这样假设来得到答案,为什么要猜测呢? - Deduplicator
谢谢你的回答。我想我会选择可读性,没有必要节省空间,只是因为我有点完美主义。 - cdonts

3
不要为了“效率”而使用char——这只会让人们感到困惑和烦恼(比如我自己:-)。对于一般的数字整数,使用int即可。
对于精确控制,例如用于8位RGB像素数组,请使用uint8_t

@Deduplicator 我的眼睛有点湿润了。位压缩已经被其他答案覆盖,所以我会擦干手走开 xD - user2864740
谢谢你的回答!+1 - cdonts

2

传递值时使用的类型几乎不重要,您应使用字节对齐类型,char很合适(尽管在几乎任何数值操作之后它可能会被上转为int,因此int可能更容易)。

当您将其存储在数组中时,应考虑将数据打包为每个值2位。


1

char非常适合存储低范围的值。当你有大量值需要处理时,它提供了高效性。除非你决定通过分区位将多个值存储在单个变量中,否则没有更小的选择,因为char是一个完整的字节...祝好运!


它提供了效率 - 在内存使用方面,可能是如此。在执行速度方面,可能相反。 - Oliver Charlesworth
我不是架构专家,但据我所知,char 只是8位。在内存和执行方面,8位比16位shorts、32位ints和64位long longs更快。 - user2105505
1
在大多数平台上,ALU 的本机宽度 > 8 位。因此,每次都必须提取 char,这可能需要花费循环周期,具体取决于架构。当然,在另一方面,如果您的程序受到内存速度的限制,那么这可能是值得的,因为您将更少使用缓存。 - Oliver Charlesworth

1

char是一种窄整数类型。它可以是有符号的,也可以是无符号的。如果它是无符号的,它的范围至少为0到255;如果它是有符号的,它的范围至少为-127到+127。(是的,-127,而不是-128;标准并不要求有符号整数使用2的补码表示)。

类型char,顾名思义,主要用于保存字符 -- 但如果你愿意,你也可以用它来保存小整数,特别是如果你知道它们只会在0到127的范围内。最好使用unsigned charsigned char

但无论如何,不要指望与使用int相比节省空间将是显著的。许多系统需要更多且更慢的代码来执行char值上的算术运算,而不是执行int值上的算术运算 -- 而且char值在大多数情况下都会被隐式提升为int。如果你需要存储大量的小整数值数组,使用某种字符类型的数组是有意义的。对于单个变量,与使用int相比使用char并不能节省多少空间,如果有的话。

你还需要记住,int 只能保证至少有16位,而不是32位。(但现在,除非你在进行嵌入式工作,否则在大多数你可能使用的系统上,它很可能是32位或更宽的。)如果你需要特定大小,那么在 <stdint.h> 中定义了许多类型(实际上是 typedefs,即现有类型的别名)。

1

关于C语言性能,没有明确的规范,所以任何答案最多只是一个指南,并且需要进行性能分析。

一般来说:

1)使用int(或unsigned)可以获得最佳速度和最小的代码大小。

2)使用最小的整数类型charsigned charunsigned char),因为它们占用最少的内存空间。除了可能不适用于0到4之外,没有比这更小的单一类型。如果您有许多这样的小对象要打包在一起,则位域可能更小。

当存在许多复制品(例如大型数组)或内存紧缺时,使用小整数类型/位域是一个好习惯。否则,代码的简洁性应优先考虑。


许多人提到了关于char的假设:
1)它可以是有符号的或无符号的。
2)它具有最小宽度为8位和最小范围为0到255 -127到127(而不是-128)。

1
我本来想问一下2的来源,但在这里找到了1:https://dev59.com/AlzUa4cB1Zd3GeqP7uch) - Foon
@Foon See C11 §5.2.4.2.1 1 & 2: signed char 的最小范围是-127到+127,而 unsigned char 的范围是0到255,其中 char 必须匹配其中之一。CHAR_BIT 至少为8。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接