7

現在、関数に渡される引数の合計サイズをバイト単位で計算しようとしています。sizeof(x)理論的には、すべての引数について書き出すことができます。ただし、多くの機能でこれを実行したい場合、これは非常に時間の無駄です。引数のスペースの量を把握して、適切な量のメモリを割り当ててすべてを格納し、格納できるようにしようとしています(さまざまな関数の場合、タイプが混在しています)。

名前や数に関係なく、非可変個引数関数のすべての引数のサイズを決定できる式を作成しようとしています(理由の範囲内で、今のところ約64個の引数のみをサポートしても問題ありません)。 )。それは関数、プリプロセッサマクロである可能性があり、私は実装にとらわれません。可変個引数関数の処理にも興味がありますが、可変個引数関数に入るまでにデータ型に関するすべての情報が失われているため、それは不可能だと確信しています。

現在、私はこれを可能にするためにねじれるかもしれない3つのアプローチを見つけました。1つ目は、 LaurentDeniauの引数カウントの概念に基づいています。理論的には、マクロを使用して関数ヘッダーを生成し、同様の凝ったフットワークを実行して、引数の数を取得し、N個の引数がある個々のケースを処理するさまざまなマクロにディスパッチできます。(参照:醜い)。基本的には、マクロを使用してすべての関数名をエイリアスし、それぞれにsizeofを使用します。問題は、表現したいすべての長さの引数に対してマクロを作成する必要があるということです。そして、私は1つの仕事をするために64(またはそれ以上)のものを作ることを本当に好まない。

2番目のアプローチは、BenKlemerの「より優れた可変個引数」のもののアプローチに従うことを試みることです。私は彼のアプローチのすべてを使用するわけではありませんが、関数のargシグニチャを構造体に表す構造体を生成しようとしています。次に、構造要素のサイズを取得することを試みることができます(または、スペースの控えめな見積もりだけを気にした場合は、構造自体も)。これにはいくつかの問題があります。まず、C99準拠のものでのみ機能する可能性があります(まだそれをチェックしています)。次に、実装されるすべての関数に追加の構造を作成します。これは完全に問題ではありませんが、構造体を作成する彼のアプローチが関数と同じ名前になるという問題があります(したがって、それらを使用するには名前を参照する必要があります)。

可能な3番目のアプローチは再帰マクロですが、それがコンパイラーをどれほど満足させるかはわかりません。理論的には、形式でマクロを呼び出すことにより、 VA_ARGSから要素を再帰的にポップすることができます。明らかに、 VA_ARGが空の場合の停止ルール(およびフローティング+記号に引っ掛からないようにするための何か)が必要ですが、あなたはその考えを理解します。POPPER(arg, ...) POPPER(VA_ARGS) + sizeof(arg)

これらのいずれかを使用すると、これを実行できます。

  1. 可変個引数マクロからVA_ARGSを解凍するための優れた柔軟な方法。インデックスを作成する方法がある場合
  2. これを行うために信頼できる再帰マクロの良い例(および引数の最大数、コンパイラの互換性、標準への準拠などの制限)。
  3. さまざまなタイプの関数検査を通じて、すべての引数の合計サイズを直接取得する方法。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)
        :

それができたら、マクロを記述してその引数のサイズを取得し、それらをチェーンして追加できます。

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

これが私が最終的に思いついたもので、最大64個の引数(または実際には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 に答える