C Функция, которая вычисляет общий размер аргументов - PullRequest
7 голосов
/ 02 июня 2011

В настоящее время я рассчитываю вычислить общий размер аргументов, передаваемых в функцию, в байтах.Теоретически, можно просто выписать sizeof(x) для каждого аргумента.Тем не менее, это огромная трата времени, если вы хотите сделать это для многих функций.Я пытаюсь определить объем пространства для аргументов, чтобы я мог выделить необходимый объем памяти для хранения их всех и хранения (для различных функций, со смешанными типами).

I 'Я собираюсь сделать выражение, которое может определять размер всех аргументов для невариантной функции, независимо от их имен и независимо от того, сколько их (в пределах разумного я в порядке, пока поддерживаю только около 64 аргументов).Это может быть функция, макрос препроцессора, я независим от реализации.Я также был бы заинтересован в обработке функций с переменными числами, но я уверен, что это невозможно, потому что к тому времени, когда вы используете функцию с переменными числами, вы теряете всю информацию о типах данных.

В настоящее времяЯ нашел три подхода, которые могут быть искажены, чтобы позволить мне сделать это.Первый основан на концепциях Аргумента Лорана Денио, считающих .Теоретически, я могу использовать макрос для генерации заголовка функции и выполнять аналогичную сложную работу, чтобы получить количество аргументов и передать их в различные макросы, которые обрабатывают КАЖДЫЙ индивидуальный случай, когда имеется N аргументов.(См .: Гадкий).По сути, я бы просто использовал псевдонимы всех имен функций с помощью макроса, а затем использовал sizeof для каждого из них.Проблема в том, что мне нужно сделать макрос для КАЖДОЙ длины аргументов, которые я хочу представить.И я бы на самом деле не предпочел бы сделать 64 (или больше) вещей для выполнения одной работы.

Второй подход - попытаться следовать подходу «лучших вариативных» вещей Бена Клемера ,Я не использовал бы весь его подход, но я бы попытался сгенерировать структуру, которая представляет подпись arg функции в структуре.Затем я мог бы попытаться получить размер элементов структуры (или даже самой структуры, если бы все, что меня беспокоило, было консервативной оценкой пространства).Это имеет несколько проблем.Во-первых, он может работать только на C99-совместимых вещах (все еще проверяя это).Во-вторых, это приводит к созданию дополнительной структуры для каждой реализованной функции.Это не совсем проблема, но все же есть проблема в том, что его подход к созданию структуры заканчивается теми же именами, что и функция (поэтому вам все равно нужно обращаться к именам, чтобы использовать их).Я, вероятно, мог бы обойти это, хотя.

Третий подход, который был бы возможен, был бы рекурсивным макросом, хотя я не уверен, насколько счастливым это делает компиляторы.Теоретически возможно рекурсивно вытолкнуть элементы из VA_ARGS , вызвав макрос в форме POPPER(arg, ...) POPPER(<strong>VA_ARGS</strong>) + sizeof(arg).Ясно, что потребуется правило остановки для случая, когда VA_ARG пусто (и что-то, чтобы убедиться, что вас не поймает плавающий знак +), но вы поймете идею.

Любая из этих вещей позволила бы мне сделать это:

  1. Хорошие, гибкие способы распаковать VA_ARGS из макроса с переменными числами.Если есть какой-либо способ индексировать его
  2. Хороший пример рекурсивного макроса, на который можно было бы полагаться при выполнении этого (а также его ограничения в отношении максимального числа аргументов, совместимости компилятора, соответствия стандартам и т. Д.).
  3. Способ непосредственного получения общего размера всех аргументов посредством проверки функций другого типа.В GCC, похоже, есть некоторые сумасшедшие функции для создания вызовов функций для переадресации вызовов, которые могут быть применимы, но они зависят от компилятора, едва документированы и, как представляется, не сообщают о размере блока памяти, который они выделяют,Они также сообщают тонны несущественной информации.

Ответы [ 2 ]

4 голосов
/ 03 июня 2011

Вам необходим макрос 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));
2 голосов
/ 16 сентября 2011

Итак, в конце я пришел к выводу, что он функционирует до 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__)
...