2011-06-02 45 views
7

我目前正在計算傳遞給函數的參數的總大小(以字節爲單位)。理論上,每個參數都可以寫出sizeof(x)。但是,如果想爲許多功能做這件事,這是一個巨大的浪費時間。我試圖找出參數的空間量,以便我可以分配適量的內存來存儲它們並存儲它們(對於具有混合類型的各種函數)。C函數計算參數的總大小

我正在尋找一個表達式,可以確定所有參數的大小,以一個非變量函數,無論他們的名稱和無論有多少(在理由,我很好,只支持現在有64個參數)。它可以是一個函數,一個預處理器宏,我對實現不可知。我也會對處理可變參數函數感興趣,但我很確定這是不可能的,因爲當你進入可變參數函數時,你已經失去了關於數據類型的所有信息。

目前,我發現三種方法可能會扭曲,讓我這樣做。第一個基於Laurent Deniau's arg counting的概念。理論上,我可以使用一個宏來生成函數頭,並且執行一些類似的花式步驟來獲取參數的數量並派發到處理每個有N個參數的每個個案的各種宏。 (見:醜)。基本上,我只是使用宏對所有函數名稱進行別名,然後在其中的每一個上使用sizeof。問題是,我需要爲每個我想表示的參數創建一個宏。而且我真的不想讓64個(或更多)的東西去完成一項工作。

第二種方法是嘗試遵循Ben Klemer's 'better variadic' stuff的方法。我不會使用他所有的方法,但我會嘗試生成一個結構體,它將一個函數的參數簽名表示爲結構體。然後,我可以嘗試獲取結構元素的大小(或者甚至是結構本身,如果我關心的是對空間的保守估計)。這有幾個問題。首先,它可能只適用於C99兼容的東西(仍在檢查)。其次,它導致爲每個實現的功能創建一個額外的結構。這並不完全是一個問題,但它仍然存在一個問題,即他構造一個結構的方法最終會使用與函數相同的名稱(因此您仍然需要引用名稱來使用它們)。不過我可以解決這個問題。

第三種方法可能是遞歸宏,儘管我不確定編譯器有多高興。理論上可以通過調用形式爲POPPER(arg, ...) POPPER(VA_ARGS) + sizeof(arg)的宏來遞歸地彈出VA_ARGS中的元素。很顯然,當VA_ARG爲空(並確保您不會被浮動+符號捕獲)時,需要暫停規則,但您明白了。

任何這些東西,讓我做到這一點:

  1. 好,靈活的方式來從宏觀可變參數解開VA_ARGS。如果有什麼辦法可以索引它
  2. 遞歸宏的一個很好的例子,它可以被用來做到這一點(以及它在最大參數,編譯器兼容性,標準符合性等方面的限制)。
  3. 一種通過不同類型的功能檢查直接獲取所有參數總大小的方法。 GCC似乎有一些crazy函數用於構建可能適用的呼叫轉移函數調用,但這些函數是特定於編譯器的,幾乎沒有記錄,並且似乎沒有報告它們分配的內存塊的大小。他們還彙報了大量不相關的信息。
+2

'sizeof()'從來沒有浪費任何時間,因爲它總是在編譯時由編譯器計算。這不是一個功能,而只是一個操作員。 – x4u 2011-06-02 18:51:53

+3

我贊成你的籌備性研究,但是你有具體的可回答的問題嗎? – 2011-06-02 18:54:24

+1

它可以通過一種或多或少的破解和/或系統/編譯器依賴的方式完成,但給你一個體面的建議,如果你能回答這個問題,那將是很好的:你打算如何處理這些信息,你什麼時候做需要它? (在運行時,編譯時間還是簡單地作爲源代碼度量?) – x4u 2011-06-02 18:56:47

回答

3

您需要一個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) 
     : 

一旦你有,你可以寫一個宏來獲得的sizeof其ARG和它們連起來,將它們添加:

#define SUM_SIZEOF(X) +sizeof(X) 
size_t size = FOREACH(SUM_SIZEOF, (int, int, double, float)); 
+0

有趣並且看起來似乎是可行的。我只是在Boost文檔中探索過,似乎他們有一些方法可以簡化ForEach風格的宏(使用一些對序列進行操作的函數)。這會是一種更乾淨的做類似的事情嗎? – Namey 2011-06-02 21:35:42

+0

這當然規定可以直接使用Boost。我還沒有嘗試過,所以這只是一個想法。 – Namey 2011-06-02 21:50:42

+0

我最終做了一些非常相似的事情,實際上,在這裏使用你的建議和類似的方法:http://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-可變參數的宏。儘管我接受了你的答案,但我會發布最終代碼作爲答案。謝謝。 – Namey 2011-09-16 15:30:35

1

所以這就是我最終想到的,它最多可以運行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__)