Pertanyaan Melewati argumen variabel ke fungsi lain yang menerima daftar argumen variabel


Jadi saya memiliki 2 fungsi yang keduanya memiliki argumen serupa

void example(int a, int b, ...);
void exampleB(int b, ...);

Sekarang example panggilan exampleB, tapi bagaimana saya bisa meneruskan variabel dalam daftar argumen variabel tanpa memodifikasi exampleB (karena ini sudah digunakan di tempat lain juga).


75
2017-08-20 12:22


asal


Jawaban:


Anda tidak dapat melakukannya secara langsung; Anda harus membuat fungsi yang membutuhkan va_list:

#include <stdarg.h>

static void exampleV(int b, va_list args);

void example(int a, int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

void exampleB(int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

static void exampleV(int b, va_list args)
{
    ...whatever you planned to have exampleB do...
    ...except it calls neither va_start nor va_end...
}

89
2017-08-20 12:28



Anda harus membuat versi dari fungsi-fungsi ini yang mengambil va_list, dan meneruskannya. Melihat vprintf sebagai contoh:

int vprintf ( const char * format, va_list arg );

15
2017-08-20 12:26



Mungkin melempar batu ke kolam di sini, tetapi tampaknya berfungsi cukup baik dengan templat variadic C ++ 11:

#include <stdio.h>

template<typename... Args> void test(const char * f, Args... args) {
  printf(f, args...);
}

int main()
{
  int a = 2;
  test("%s\n", "test");
  test("%s %d %d %p\n", "second test", 2, a, &a);
}

Paling tidak, ia bekerja dengan g++.


9
2017-09-16 13:42



Kebetulan, banyak implementasi C memiliki variasi vf printf internal yang IMHO seharusnya menjadi bagian dari standar C. Rincian yang tepat bervariasi, tetapi implementasi khas akan menerima struct yang berisi pointer fungsi karakter-output dan informasi yang mengatakan apa yang seharusnya terjadi. Ini memungkinkan printf, sprintf, dan fprintf untuk semua menggunakan mekanisme 'inti' yang sama. Misalnya, vsprintf mungkin seperti:

void s_out (PRINTF_INFO * p_inf, char ch)
{
  (* (p_inf-> destptr) ++) = ch;
  p_inf-> hasil ++;
}

int vsprintf (char * dest, const char * fmt, va_list args)
{
  PRINTF_INFO p_inf;
  p_inf.destptr = dest;
  p_inf.result = 0;
  p_inf.func = s_out;
  core_printf (& p_inf, fmt, args);
}

Fungsi core_printf kemudian memanggil p_inf-> func untuk setiap karakter menjadi output; fungsi output kemudian dapat mengirim karakter ke konsol, file, string, atau yang lain. Jika implementasi seseorang mengekspos fungsi core_printf (dan mekanisme pengaturan apa pun yang digunakan) seseorang dapat memperpanjangnya dengan segala macam variasi.


2
2017-08-20 14:34



Saya juga ingin membungkus printf dan menemukan jawaban yang membantu di sini:

Bagaimana cara melewati sejumlah variabel argumen ke printf / sprintf

Saya sama sekali tidak tertarik pada kinerja (saya yakin potongan kode ini dapat ditingkatkan dalam beberapa cara, jangan ragu untuk melakukannya :)), ini hanya untuk debugger umum, jadi saya melakukan ini:

//Helper function
std::string osprintf(const char *fmt, ...)
{
    va_list args;
    char buf[1000];
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args );
    va_end(args);
    return buf;
}

yang kemudian bisa saya gunakan seperti ini

Point2d p;

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";

C ++ ostreams itu indah dalam beberapa aspek, tetapi praktis menjadi mengerikan jika Anda ingin mencetak sesuatu seperti ini dengan beberapa string kecil seperti kurung, titik dua dan koma yang disisipkan di antara angka-angka.


2
2018-01-07 19:22



Berdasarkan komentar yang Anda ikat vsprintf, dan ini ditandai sebagai C ++ Saya sarankan untuk tidak mencoba melakukan ini, tetapi ubah antarmuka Anda untuk menggunakan C ++ iostreams sebagai gantinya. Mereka memiliki kelebihan di atas print garis fungsi, seperti jenis keamanan dan mampu mencetak barang-barang itu printf tidak akan bisa menangani. Beberapa pengerjaan ulang sekarang dapat menghemat banyak rasa sakit di masa depan.


0
2017-08-20 13:34



Dengan menggunakan standar C ++ 0x yang baru, Anda mungkin bisa menyelesaikannya menggunakan templat variadic atau bahkan mengonversi kode lama ke sintaks template baru tanpa merusak apa pun.


-1
2017-08-20 12:56