7

我目前正在寻找以字节为单位计算传递给函数的参数的总大小。理论上,一个人可以写出sizeof(x)每一个论点。但是,如果要为很多功能执行此操作,这将是极大的浪费时间。我试图找出参数的空间量,以便我可以分配适量的内存来存储它们并存储它们(用于各种函数,具有混合类型)。

我正在寻找一个表达式,可以确定非可变参数函数的所有参数的大小,无论它们的名称如何,也不管有多少(在合理的范围内,我现在只支持大约 64 个参数很好)。它可以是一个函数,一个预处理器宏,我不知道它的实现。我也对处理可变参数函数感兴趣,但我很确定这是不可能的,因为当你进入可变参数函数时,你已经丢失了有关数据类型的所有信息。

目前,我发现了三种可能会被扭曲让我这样做的方法。第一个是基于Laurent Deniau 的 arg 计数的概念。理论上,我可以使用宏来生成函数头,并做一些类似的花哨的步骤来获取 args 的数量并分派给处理每个有 N 个参数的个别情况的各种宏。(见:丑)。基本上,我只是使用宏给所有函数名起别名,然后在每个函数名上使用 sizeof。问题是,我需要为我想要表示的每个长度的参数创建一个宏。而且我真的不喜欢做 64 件(或更多)事情来完成一项工作。

第二种方法是尝试遵循Ben Klemer 的“更好的可变参数”的方法。我不会使用他的所有方法,但我会尝试生成一个结构,该结构将函数的 arg 签名表示为结构。然后我可以尝试获取结构元素的大小(甚至结构本身,如果我关心的只是对空间的保守估计)。这有几个问题。首先,它可能只适用于符合 C99 的东西(仍在检查中)。其次,它导致为每个实现的功能创建一个额外的结构。这不完全是个问题,但仍然存在问题,即他制作结构的方法最终与函数的名称相同(因此您仍然需要引用名称才能使用它们)。

第三种可能的方法是递归宏,尽管我不确定编译器有多高兴。理论上可以通过调用形式为 的宏递归地从VA_ARGS中弹出元素。显然,当VA_ARG为空时需要一个暂停规则(以及确保您不会被浮动 + 符号抓住的东西),但您明白了。POPPER(arg, ...) POPPER(VA_ARGS) + sizeof(arg)

这些事情中的任何一件都可以让我这样做:

  1. 从可变参数宏中解压缩VA_ARGS的良好、灵活的方法。如果有任何方法可以索引它
  2. 可以依赖递归宏的一个很好的例子(以及它在最大参数数量、编译器兼容性、标准合规性等方面的限制)。
  3. 一种通过不同类型的函数检查直接获取所有 args 总大小的方法。GCC 似乎有一些疯狂的函数来构建可能适用的呼叫转发的函数调用,但这些是特定于编译器的,几乎没有文档记录,并且似乎没有报告它们分配的内存块的大小。他们还报告了大量不相关的信息。
4

2 回答 2

4

您需要一个 FOREACH 宏,它允许在可变参数列表的每个元素上扩展另一个宏。这通过为每个感兴趣的列表长度定义变体来工作:

#define _NUM_ARGS(X100, X99, X98, X97, X96, X95, X94, X93, X92, X91, X90, X89, X88, X87, X86, X85, X84, X83, X82, X81, X80, X79, X78, X77, X76, X75, X74, X73, X72, X71, X70, X69, X68, X67, X66, X65, X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, X53, X52, X51, X50, X49, X48, X47, X46, X45, X44, X43, X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, ...)   N
#define NUM_ARGS(...) _NUM_ARGS(__VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define EXPAND(X)             X
#define FIRSTARG(X, ...)      (X)
#define RESTARGS(X, ...)      (__VA_ARGS__)
#define FOREACH(MACRO, LIST)  FOREACH_(NUM_ARGS LIST, MACRO, LIST)
#define FOREACH_(N, M, LIST)  FOREACH__(N, M, LIST)
#define FOREACH__(N, M, LIST) FOREACH_##N(M, LIST)
#define FOREACH_1(M, LIST)    M LIST
#define FOREACH_2(M, LIST)    EXPAND(M FIRSTARG LIST) FOREACH_1(M, RESTARGS LIST)
#define FOREACH_3(M, LIST)    EXPAND(M FIRSTARG LIST) FOREACH_2(M, RESTARGS LIST)
        :

一旦你有了它,你可以编写一个宏来获取它的 arg 的大小并将它们链接在一起以添加它们:

#define SUM_SIZEOF(X)  +sizeof(X)
size_t size = FOREACH(SUM_SIZEOF, (int, int, double, float));
于 2011-06-02T20:54:30.957 回答
2

所以这就是我最后想出的,它最多可以使用 64 个 args(或者你愿意定义 FOR 和 COUNT_ARGS 函数的数量,真的)。所以,谢谢你的帮助。希望这些花絮对其他人有所帮助——它们代表了我对在网络上传播的一些伟大想法的安排。

我使 FOR_EACH 结构更通用一点,这样我就可以将它用于其他东西(例如,仅通过更改前缀和后缀来进行乘法等)。


/* CONCATENATE from Gregory Pakosz
    Source: http://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
*/

#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2)  arg1##arg2

/*  ---------------------------------
    |    Variadic/Iteration Macros   | 
    ---------------------------------*/

/*****************************************************
 COUNT_ARGUMENTS Counts the number of args to a variadic function, up to 64 (renamed from PP_NARG)
 Description: P_NARG macro returns the number of arguments that have been passed to it.
 Author: Laurent Deniau
 Source: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb?hl=en%29
 NOTE: This may not work reliably if the function receives zero args, depending on compiler
*******************************************************/

#define COUNT_ARGUMENTS(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N
#define PP_RSEQ_N() \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0


/*****************************************************
 FOR_EACH_COMPOSER Composition macro to create expressions where some sequence is bound by prefix  postfix
 Description: For each macro, but built more generally to allow expressing sums as well as series of functions.
 Adapted from: Gregory Pakosz
 Source: http://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
 Functional up to 64 arguments.
*******************************************************/

#define FOR_EACH_COMPOSER_1(prefix, postfix, finalPrefix, finalPostfix, x, ...) finalPrefix(x)finalPostfix
#define FOR_EACH_COMPOSER_2(prefix, postfix, finalPrefix, finalPostfix, x, ...)\
  prefix(x)postfix\
  FOR_EACH_COMPOSER_1(prefix, postfix, finalPrefix, finalPostfix, __VA_ARGS__)
#define FOR_EACH_COMPOSER_3(prefix, postfix, finalPrefix, finalPostfix, x, ...)\
  prefix(x)postfix\
  FOR_EACH_COMPOSER_2(prefix, postfix, finalPrefix, finalPostfix, __VA_ARGS__)

/* Etc, up to 64 */

#define FOR_EACH_COMPOSER_(N, prefix, postfix, finalPrefix, finalPostfix, ...) CONCATENATE(FOR_EACH_COMPOSER_, N)(prefix, postfix, finalPrefix, finalPostfix, __VA_ARGS__)

#define FOR_EACH_COMPOSER(prefix, postfix, finalPrefix, finalPostfix, ...) FOR_EACH_COMPOSER_(COUNT_ARGUMENTS(__VA_ARGS__), prefix, postfix, finalPrefix, finalPostfix, __VA_ARGS__)

/*****************************************************
 SIZE_OF_ARGUMENTS Calculates the size of the given arguments
 Description: For each argument, calculates the sizeof returns the sum
 Author: Benjamin Nye
 NOTE: This may not work reliably if the function receives zero args, depending on compiler
*******************************************************/
#define SIZE_OF_ARGS(...) FOR_EACH_COMPOSER(sizeof , +, sizeof , + 0, __VA_ARGS__)
于 2011-09-16T15:44:55.433 回答