একটি ভেরিয়েবল আর্গুমেন্ট তালিকা গ্রহণ করে এমন অন্য ফাংশনে ভেরিয়েবল আর্গুমেন্টগুলি পাস করা


114

সুতরাং আমি 2 ফাংশন যে উভয় একই যুক্তি আছে

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

এখন exampleকল exampleB, তবে আমি পরিবর্তনশীল ছাড়াই চলক আর্গুমেন্ট তালিকার ভেরিয়েবলগুলি কীভাবে পাশ করতে পারি exampleB(এটি ইতিমধ্যে অন্য কোথাও ব্যবহৃত হয়েছে)।



2
ঠিক আছে যে এর সমাধানটি ভিপ্রিন্টফ ব্যবহার করছিল, এবং এটি এখানে নেই।
পাওয়া যায় না

উত্তর:


127

আপনি সরাসরি এটি করতে পারবেন না; আপনাকে একটি ফাংশন তৈরি করতে হবে যা একটি গ্রহণ করে va_list:

#include <stdarg.h>

static void exampleV(int b, va_list args);

void exampleA(int a, int b, ...)    // Renamed for consistency
{
    va_list args;
    do_something(a);                // Use argument a somehow
    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...
}

2
সন্দেহজনকভাবে আমাকে এরকম কিছু করতে হয়েছিল, সমস্যাটি হ'ল উদাহরণ ফাংশনটি মূলত vspprf এর জন্য একটি মোড়ক এবং অন্য কিছু নয়: /
উপলভ্য নেই

@ জেরোস: নোট করুন যে এটি উদাহরণ বি কী করে তার বাহ্যিক স্পেসিফিকেশন পরিবর্তন করে না - এটি কেবল অভ্যন্তরীণ বাস্তবায়নকে পরিবর্তন করে। সমস্যাটি কী তা আমি নিশ্চিত নই।
জোনাথন লেফলার

প্রথম প্যারামিটারটি প্রয়োজনীয় বা সমস্ত পরামিতিগুলি বৈচিত্রপূর্ণ হতে পারে?
কিওয়ার্টি

1
@ কিওয়ার্টি: সিনট্যাক্সটির একটি ফাংশনে একটি নামযুক্ত প্রথম যুক্তি প্রয়োজন , ...যা স্বাক্ষর সহ একটি পরিবর্তনীয় আর্গুমেন্ট তালিকা গ্রহণ করে। আপনি যদি ভেরিয়েবল আর্গুমেন্টগুলিকে একটিতে রূপান্তর করেন va_listতবে va_listআপনি অন্য কোনও ফাংশনে পাস করতে পারেন যা কেবল একটি গ্রহণ করে va_listতবে সেই ফাংশনটি (বা এটি যে এটি বলে) অবশ্যই এর মধ্যে কী আছে তা জানার কিছু উপায় থাকতে হবে va_list
জোনাথন লেফলার

46

সম্ভবত এখানে একটি পুকুরে একটি শিল নিক্ষেপ করুন, তবে এটি সি ++ 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);
}

খুব কমপক্ষে, এটি সাথে কাজ করে g++


আমি বিভ্রান্ত - এটি কি সি ++> = 11 ব্যবহার করে বৈধ পদ্ধতির?
ডানকান জোন্স

@DuncanJones হ্যাঁ, প্যাক দ্বারা প্রসারিত পরারargs...
এক ধরনের সামুদ্রিক মাছ

15

আপনার এই ফাংশনগুলির সংস্করণ তৈরি করা উচিত যা কোনও ভিএলিস্ট নেয় এবং সেগুলি পাস করে। vprintfউদাহরণ হিসাবে দেখুন :

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

5

আমি প্রিন্টএফ মোড়তে চেয়েছিলাম এবং এখানে একটি সহায়ক উত্তর পেয়েছি:

কীভাবে প্রিন্টফ / স্প্রিন্টেফে চলক সংখ্যক আর্গুমেন্ট পাস করতে হয়

আমি পারফরম্যান্সে মোটেও আগ্রহী ছিলাম না (আমি নিশ্চিত যে এই কোডের টুকরোটি বিভিন্ন উপায়ে উন্নত করা যেতে পারে, নিখরচায় অনুভব করুন :)), এটি কেবল সাধারণ ডিবাগপ্রিন্টিংয়ের জন্য তাই আমি এটি করেছি:

//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;
}

যা আমি এর পরে ব্যবহার করতে পারি

Point2d p;

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

সি ++ অস্ট্রিমগুলি কিছু দিক থেকে সুন্দর তবে আপনি যদি কিছু ছোট স্ট্রিং যেমন বন্ধনী, কলোন এবং সংখ্যার মধ্যে comোকানো কমা দিয়ে এমন কিছু মুদ্রণ করতে চান তবে কার্যত ভয়ঙ্কর হয়ে ওঠে।


2

ঘটনাচক্রে, অনেক সি বাস্তবায়নের একটি অভ্যন্তরীণ v? প্রিন্টফ প্রকরণ রয়েছে যা আইএমএইচওর উচিত সি স্ট্যান্ডার্ডের অংশ হওয়া উচিত। সঠিক বিশদগুলি পরিবর্তিত হয়, তবে একটি সাধারণ বাস্তবায়ন একটি চরিত্র-আউটপুট ফাংশন পয়েন্টার এবং তথ্য সম্বলিত একটি স্ট্রাক্ট গ্রহণ করবে যা হ'ল যা হওয়ার কথা। এটি প্রিন্টফ, স্প্রিন্টফ এবং এফপ্রিন্টফকে একই 'কোর' মেকানিজম ব্যবহার করতে দেয়। উদাহরণস্বরূপ, ভিএসপ্রিন্টফ এমন কিছু হতে পারে:

অকার্যকর s_out (PRINTF_INFO * p_inf, চর CH)
{
  (* (p_inf-> ডেস্প্ট্রার) ++) = চি;
  p_inf-> ফলাফলের ++,;
}

ইন্টি ভিএসপ্রিন্টফ (চর * ডেস্ট, কনস্ট চর * এফএমটি, ভিএলিস্ট আরগস)
{
  PRINTF_INFO p_inf;
  p_inf.destptr = গন্তব্য;
  p_inf.result = 0;
  p_inf.func = s_out;
  core_printf (& p_inf, FMT, args);
}

কোর_প্রিন্টফ ফাংশন তারপরে প্রতিটি অক্ষরের আউটপুট হওয়ার জন্য p_inf-> func কল করে; আউটপুট ফাংশন কনসোল, একটি ফাইল, একটি স্ট্রিং, বা অন্য কোনও কিছুতে অক্ষরগুলি প্রেরণ করতে পারে। যদি এর বাস্তবায়নটি কোর_প্রিন্টফ ফাংশনটি (এবং এটির যে কোনও সেটআপ পদ্ধতি ব্যবহার করে) প্রকাশ করে তবে যে কোনও প্রকারের তারতম্যের সাথে এটি প্রসারিত করতে পারে।


1

একটি সম্ভাব্য উপায় # ডিফাইন ব্যবহার করা:

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)

0

আপনি মোড়ানো হয়ে গেছেন এমন মন্তব্যের ভিত্তিতে vsprintfএবং এটি সি ++ হিসাবে ট্যাগ হয়েছে আমি এটি করার চেষ্টা না করার পরামর্শ দিচ্ছি, তবে পরিবর্তে সি ++ আইস্ট্রিমে ব্যবহার করার জন্য আপনার ইন্টারফেসটি পরিবর্তন করব। printটাইপ সুরক্ষা এবং printfহ্যান্ডেল করতে সক্ষম হবে না এমন আইটেমগুলি মুদ্রণ করতে সক্ষম হওয়ার মতো ফাংশনের লাইনে তাদের সুবিধা রয়েছে । কিছু পুনর্নির্মাণ এখন ভবিষ্যতে উল্লেখযোগ্য পরিমাণে ব্যথা বাঁচাতে পারে।


আপনি কি সুবিধা উল্লেখ করছেন?
সিজকিরি

@ সিজেকিউরি: সুবিধাটি ব্যবহারকারীর সংজ্ঞায়িত প্রকারের সাথে সুরক্ষার প্রকার। সি ফাংশন অবশ্যই ব্যবহারকারী-সংজ্ঞায়িত প্রকারগুলি হ্যান্ডেল করতে পারে না।
জোনাথন লেফলার

-1

নতুন সি ++ 0 এক্স স্ট্যান্ডার্ড ব্যবহার করে, আপনি ভেরিয়াদিক টেম্পলেট ব্যবহার করে এটি করতে সক্ষম হতে পারেন বা এমনকি কিছু পুরানো কোডটি নতুন কিছু টেম্পলেট বিন্যাসে রূপান্তর করতে পারেন।


দুর্ভাগ্যক্রমে সমস্ত ক্ষেত্রে এটি সম্ভব নয় - কেবল
ল্যাম্বডাস

-1

এটি করার একমাত্র উপায় এটি এবং এটি করারও সর্বোত্তম উপায় ..

static BOOL(__cdecl *OriginalVarArgsFunction)(BYTE variable1, char* format, ...)(0x12345678); //TODO: change address lolz

BOOL __cdecl HookedVarArgsFunction(BYTE variable1, char* format, ...)
{
    BOOL res;

    va_list vl;
    va_start(vl, format);

    // Get variable arguments count from disasm. -2 because of existing 'format', 'variable1'
    uint32_t argCount = *((uint8_t*)_ReturnAddress() + 2) / sizeof(void*) - 2;
    printf("arg count = %d\n", argCount);

    // ((int( __cdecl* )(const char*, ...))&oldCode)(fmt, ...);
    __asm
    {
        mov eax, argCount
        test eax, eax
        je noLoop
        mov edx, vl
        loop1 :
        push dword ptr[edx + eax * 4 - 4]
        sub eax, 1
        jnz loop1
        noLoop :
        push format
        push variable1
        //lea eax, [oldCode] // oldCode - original function pointer
        mov eax, OriginalVarArgsFunction
        call eax
        mov res, eax
        mov eax, argCount
        lea eax, [eax * 4 + 8] //+8 because 2 parameters (format and variable1)
        add esp, eax
    }
    return res;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.