2

假设我得到了一个具有以下签名的函数:

void SendBytesAsync(unsigned char* data, T length)

我需要一个足够大的缓冲区来容纳可以由 type 指定的最大长度的字节数组T。如何声明该缓冲区?我不能只使用sizeof它,因为它将返回 T 类型的大小(以字节为单位),而不是该类型可以包含的最大值。我不想使用limits.h,因为基础类型可能会改变并且我的缓冲区太小。我不能使用 math.h 中的 pow 因为我需要一个常量表达式。那么如何在 C 的编译时获得一个类型的最大大小的常量表达式呢?

编辑

该类型将是无符号的。由于每个人似乎都对在编译时确定的静态分配缓冲区的想法感到震惊,所以我将提供一些背景知识。这适用于可靠性和速度是优先考虑的嵌入式应用程序(在微控制器上)。malloc因此,为了运行时完整性(没有问题)和性能(每次我需要缓冲区时没有内存分配开销),我完全可以浪费静态分配的内存。我理解如果最大大小T太大我的链接器将无法分配那么大的缓冲区的风险,但这将是编译时失败,可以适应,而不是运行时失败,这不能容忍。例如,如果我使用size_t对于有效负载的大小和动态分配内存,系统很有可能没有那么多可用内存。我宁愿在编译时知道这一点,而不是在运行时这会导致数据包丢失、数据损坏等。看看我提供的函数签名,提供一个类型作为动态的大小参数是荒谬的分配的缓冲区并且不期望调用者将使用该类型的最大值的可能性。所以我不知道为什么似乎有这么多关于分配内存的惊愕,永远。我可以看到这在 Windows 世界中是一个巨大的问题,其中多个进程正在争夺相同的内存资源,但在嵌入式世界中,只有一项任务需要完成,如果你不能有效地做到这一点,那么它就不会。

4

5 回答 5

4

使用_Generic

#define MAX_SIZE(X) _Generic((X),
                             long: LONG_MAX,
                             unsigned long: ULONG_MAX,
                             /* ... */)

在 C11 之前,没有一种可移植的方法来找到 T 类型对象的精确最大值(CHAR_BIT例如,所有使用 的计算都可能由于填充位而产生高估)。

编辑:请注意,在某些条件下(想想现实生活中的分段内存),您可能无法分配足够大的缓冲区以等于任何给定类型 T 的最大值。

于 2012-08-20T21:10:17.400 回答
2

您是否有理由分配最大可能的缓冲区大小而不是仅与您需要一样大的缓冲区?为什么不让调用者简单地指定所需的内存量?

回想一下,该malloc()函数接受一个类型为 的参数size_t。这意味着(size_t)(-1)SIZE_MAX在 C99 及更高版本中)将表示可以传递给malloc. 如果您malloc用作分配器,那么这将是您的绝对上限。

于 2012-08-20T21:24:25.470 回答
2

如果 T 是无符号的,那么 ((T) -1) 会起作用吗?

(这可能真的很糟糕,如果是这样,请告诉我原因:-))

于 2012-08-20T21:03:19.570 回答
1

也许尝试使用位移?

让我们来看看:

unsigned long max_size = (1 << (8 * sizeof(T))) - 1

sizeof(T) 为您提供 T 在内存中占用的字节数。(技术上不正确。通常编译器会将结构与内存对齐......所以如果 T 是一个字节,它实际上会分配 4 或其他东西。)

分解它:

8 * sizeof(T)给你 size 代表的位数

1 << x是一样的说法2 to the x power。因为每次你向左移动,你就乘以 2。就像每次以 10 为基数向左移动一样,您乘以 10。

- 1一个 8 位数可以容纳 256 个值。0..255。

于 2012-08-20T21:07:06.730 回答
0

有趣的问题。我将首先在“限制”标题中查找数字类型 T 的最大值。我没有尝试过,但我会做一些使用 T::max 的事情

于 2012-08-20T21:07:03.623 回答