[英]Declare array large enough to hold a type
假设我有一个带有以下签名的函数:
void SendBytesAsync(unsigned char* data, T length)
我需要一个足够大的缓冲区来保存一个可由类型T
指定的最大长度的字节数组。 我如何声明缓冲区? 我不能只使用sizeof
,因为它将返回类型T的大小(以字节为单位),而不是类型可能包含的最大值。 我不想使用limits.h,因为底层类型可能会改变,而我的缓冲区太小。 我不能使用math.h中的pow,因为我需要一个常量表达式。 那么如何在C中编译时获得类型最大大小的常量表达式?
该类型将是未签名的。 由于每个人似乎对在编译时确定的静态分配缓冲区的想法感到震惊,我将提供一些背景知识。 这适用于以可靠性和速度为优先级的嵌入式应用(在微控制器上)。 因此,为了运行时完整性(没有malloc
问题)和性能(每次需要缓冲区时内存分配没有开销),我完全可以浪费静态分配的内存。 我理解如果T
的最大大小太大,我的链接器将无法分配大的缓冲区的风险,但这将是编译时失败,可以适应,而不是运行时故障,这是不能容忍的。 例如,如果我使用size_t
作为有效载荷的大小并动态分配内存,那么系统很可能没有那么多可用的内存。 我宁愿在编译时知道这一点,而不是在运行时会导致数据包丢失,数据损坏等。看看我提供的函数签名,提供一个类型作为动态的大小参数是荒谬的分配缓冲区并且不期望调用者将使用该类型的最大值的可能性。 所以我不确定为什么一次分配那个内存似乎有这么多的惊愕,好的。 我可以看到这在Windows世界中是一个巨大的问题,其中多个进程正在为相同的内存资源而战,但在嵌入式世界中,只有一项任务要完成,如果你不能有效地做到这一点,那么它就不会你节省了多少记忆。
使用_Generic
:
#define MAX_SIZE(X) _Generic((X),
long: LONG_MAX,
unsigned long: ULONG_MAX,
/* ... */)
在C11之前,没有一种可移植的方法来查找类型为T的对象的确切最大值(例如,所有使用CHAR_BIT
计算都可能因填充位而产生过高估计)。
编辑:请注意,在某些条件下(想想现实情况的分段存储器),您可能无法分配足够大的缓冲区以等于任何给定类型T的最大值。
如果T是无符号的,那么((T)-1)会工作吗?
(这可能真的很糟糕,如果是这样,请告诉我原因:-))
您是否有理由分配最大可能的缓冲区大小而不是只需要大小的缓冲区? 为什么不让调用者只是指定所需的内存量?
回想一下, malloc()
函数接受一个size_t
类型的参数。 这意味着(size_t)(-1)
(在C99及更高版本中为SIZE_MAX
)将表示可以传递给malloc
最大值。 如果您使用malloc
作为分配器,那么这将是您的绝对上限。
也许尝试使用一点移位?
让我们来看看:
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。
有趣的问题。 我将首先在'limits'标题中查找数值类型T的最大值。我没有尝试过,但我会做一些使用T :: max的东西
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.