假设我有一个带有以下签名的函数:
void SendBytesAsync(unsigned char* data, T length)
我需要一个足够大的缓冲区来保存一个可以由T
类型指定的最大长度的字节数组。我如何声明缓冲区?我不能只使用sizeof
因为它将返回类型T的大小(以字节为单位)而不是该类型可以包含的最大值。我不想使用limits.h,因为底层类型可能会改变,而我的缓冲区太小。我不能使用math.h中的pow,因为我需要一个常量表达式。那么如何在C?
该类型将是未签名的。由于每个人似乎对在编译时确定的静态分配缓冲区的想法感到震惊,我将提供一些背景知识。这适用于以可靠性和速度为优先级的嵌入式应用(在微控制器上)。因此,为了运行时完整性(没有malloc
问题)和性能(每次我需要缓冲区时内存分配没有开销),我完全可以浪费静态分配的内存。我理解如果T
的最大大小太大,我的链接器将无法分配大的缓冲区,但这将是编译时失败,可以适应,而不是运行的风险时间失败,这是不能容忍的。例如,如果我使用size_t
作为有效载荷的大小并动态分配内存,那么系统很可能没有那么多可用内存。我宁愿在编译时知道这一点,而不是在运行时会导致数据包丢失,数据损坏等。看看我提供的函数签名,提供一个类型作为动态的大小参数是荒谬的分配缓冲区并且不期望调用者将使用该类型的最大值的可能性。所以我不确定为什么一次分配那个内存似乎有这么多的惊愕,好的。我可以看到这在Windows世界中是一个巨大的问题,其中多个进程正在为相同的内存资源而战,但在嵌入式世界中,只有一项任务要完成,如果你不能有效地做到这一点,那么它就不会无论你节省了多少记忆。
答案 0 :(得分:4)
使用_Generic
:
#define MAX_SIZE(X) _Generic((X),
long: LONG_MAX,
unsigned long: ULONG_MAX,
/* ... */)
在C11之前,没有一种可移植的方法来查找类型为T的对象的确切最大值(例如,所有带CHAR_BIT
的计算都可能因填充位而产生过高的估计值。)
编辑:请注意,在某些条件下(想想现实生活情况的分段存储器),您可能无法分配足够大的缓冲区以等于任何给定类型T的最大值。
答案 1 :(得分:2)
如果T是无符号的,则((T)-1)会工作吗?
(这可能真的很糟糕,如果是这样,请让我知道原因:-))
答案 2 :(得分:2)
是否有理由分配最大可能的缓冲区大小而不是只需要大小的缓冲区?为什么不让调用者只是指定所需的内存量?
回想一下malloc()
函数采用size_t
类型的参数。这意味着(size_t)(-1)
(在C99及更高版本中为SIZE_MAX
)将代表可传递给malloc
的最大值。如果您使用malloc
作为分配器,那么这将是您的绝对上限。
答案 3 :(得分:1)
也许尝试使用位移?
让我们看看:
unsigned long max_size = (1 << (8 * sizeof(T))) - 1
sizeof(T)给出了T在内存中占用的字节数。 (技术上不正确。通常编译器会将结构与内存对齐...所以如果T是一个字节,它实际上会分配4或其他东西。)
打破它:
8 * sizeof(T)
为您提供大小代表的位数
1 << x
与2 to the x power
相同。因为每次你向左移动,你都会乘以2。就像每次在基数10中向左移动一样,你将乘以10。
- 1
一个8位数字可以容纳256个值。 0..255
答案 4 :(得分:0)
有趣的问题。我将首先在'limits'标题中查找数值类型T的最大值。我没有尝试过,但我会做一些使用T :: max
的东西