Pertanyaan C Fungsi yang menghitung ukuran total argumen


Saat ini saya ingin menghitung ukuran total argumen yang dilewatkan ke fungsi, dalam byte. Secara teori, seseorang hanya bisa menulis sizeof(x) untuk setiap argumen. Namun, ini adalah pemborosan waktu jika seseorang ingin melakukan ini untuk banyak fungsi. Saya mencoba mencari tahu jumlah ruang untuk argumen sehingga saya dapat mengalokasikan jumlah memori yang tepat untuk menyimpan semua dan menyimpannya (untuk berbagai fungsi, dengan tipe campuran).

Saya mencari untuk membuat ekspresi yang dapat menentukan ukuran semua argumen ke fungsi non-variadic, terlepas dari nama mereka dan terlepas dari berapa banyak yang ada (dalam alasan, saya baik-baik saja dengan mendukung hanya sekitar 64 argumen untuk saat ini ). Ini bisa menjadi fungsi, makro preprocessor, saya agnostik untuk implementasi. Saya juga tertarik untuk menangani fungsi-fungsi variadic, tapi saya cukup yakin itu tidak mungkin karena pada saat Anda berada dalam fungsi variadic Anda kehilangan semua informasi tentang tipe data.

Saat ini, saya telah menemukan tiga pendekatan yang mungkin dipelintir untuk membiarkan saya melakukan ini. Yang pertama didasarkan pada konsep dari Argumentasi Laurent Deniau. Secara teori, saya bisa menggunakan makro untuk menghasilkan header fungsi, dan melakukan beberapa langkah kaki mewah serupa untuk mengambil jumlah arg dan pengiriman ke berbagai makro yang menangani SETIAP kasus individu di mana ada argumen N. (Lihat: Jelek). Pada dasarnya, saya hanya akan menghapus semua nama fungsi menggunakan makro dan kemudian menggunakan sizeof pada masing-masing dari mereka. Masalahnya adalah, saya harus membuat makro untuk setiap argumen yang ingin saya wakili. Dan saya benar-benar tidak suka membuat 64 (atau lebih) hal-hal untuk melakukan satu pekerjaan.

Pendekatan kedua adalah mencoba mengikuti pendekatan Hal-hal 'baik variadic' Ben Klemer. Saya tidak akan menggunakan semua pendekatannya, tetapi saya akan mencoba untuk menghasilkan struct yang mewakili tanda argumen dari suatu fungsi ke dalam struktur. Saya kemudian dapat mencoba untuk mendapatkan ukuran dari elemen struktur (atau bahkan struktur itu sendiri, jika yang saya pedulikan adalah perkiraan konservatif dari ruang). Ini memiliki beberapa masalah. Pertama, ia hanya dapat bekerja pada hal-hal yang memenuhi C99 (masih memeriksa itu). Kedua, itu mengarah pada penciptaan struktur tambahan untuk setiap fungsi yang diterapkan. Itu tidak sepenuhnya masalah, tetapi masih memiliki masalah bahwa pendekatannya untuk membuat struct berakhir dengan nama yang sama dengan fungsi (jadi Anda masih perlu merujuk ke nama untuk menggunakannya). Saya mungkin bisa mengatasi itu.

Pendekatan ketiga yang mungkin akan menjadi makro rekursif, meskipun saya tidak yakin bagaimana senangnya membuat kompiler. Secara teoritis mungkin untuk secara rekursif elemen pop off VA_ARGS dengan memanggil makro dalam formulir POPPER(arg, ...) POPPER(VA_ARGS) + sizeof(arg). Jelas, itu akan membutuhkan aturan yang terhenti untuk kapan VA_ARG kosong (dan sesuatu untuk memastikan Anda tidak tertangkap dengan tanda + mengambang), tetapi Anda mendapatkan ide.

Salah satu dari hal-hal ini akan memungkinkan saya melakukan ini:

  1. Bagus, cara fleksibel untuk membongkar VA_ARGS dari makro variadic. Jika ada cara untuk mengindeksnya
  2. Contoh bagus dari makro rekursif yang dapat diandalkan untuk melakukan ini (serta keterbatasannya dalam jumlah maksimal, kompatibilitas kompilator, kepatuhan standar, dll).
  3. Cara untuk langsung mendapatkan ukuran total dari semua argumen melalui jenis pemeriksaan fungsi yang berbeda. GCC tampaknya memiliki beberapa gila fungsi untuk membangun fungsi panggilan untuk call forwarding yang mungkin berlaku, tetapi ini adalah khusus-kompilator, hampir tidak didokumentasikan, dan tidak muncul untuk melaporkan ukuran blok memori yang mereka alokasikan. Mereka juga melaporkan kembali banyak informasi yang tidak relevan.

7
2018-06-02 18:48


asal


Jawaban:


Anda membutuhkan makro FOREACH yang memungkinkan perluasan makro lain pada setiap elemen dari daftar variadic. Ini berfungsi dengan menentukan varian untuk setiap panjang daftar minat:

#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)
        :

Setelah Anda memilikinya, Anda dapat menulis makro untuk mendapatkan ukuran argumennya dan menggabungkannya bersama-sama untuk menambahkannya:

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

3
2018-06-02 20:54



Jadi inilah yang akhirnya saya temukan, dengan fungsi hingga 64 args (atau sebanyak Anda mau mendefinisikan fungsi FOR dan COUNT_ARGS, benar-benar). Jadi, terima kasih atas bantuannya. Semoga tidbits ini bermanfaat bagi orang lain - mereka mewakili pengaturan saya dari beberapa ide hebat yang tersebar di seluruh web.

Saya membuat konstruksi FOR_EACH sedikit lebih umum, sehingga saya bisa menggunakannya untuk hal-hal lain (misalnya perkalian, dll dengan hanya mengubah awalan dan postfix).


/* 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__)

1
2017-09-16 15:44