2010-07-28 19 views
13

मैं एक समारोहबनाएं va_list गतिशील

void foo(int cnt, va_list ap); 

मैं इसे उपयोग करने की आवश्यकता है, लेकिन आवश्यकता काफी सख्त है, va_list की संख्या भिन्न है और यह रन-टाइम के दौरान बदल जाएगा। मुझे क्या करना चाहते हैं:

एक va_list (जो उम्मीद char*) प्रपत्र

QList<Contact*> 

जहां Contact एक परिभाषित वर्ग

class Contact 
{ 
    public: 
     QString getName(); 
    private: 
     QString m_name; 

}; 

है बना सकते हैं और मैं पाश में पॉप्युलेट करने के लिए चाहते हैं उदाहरण के लिए va_list:

for (int idx = 0; idx<contacts.count(); idx++) 
{ 
    contacts.at(idx)->getName(); // this i would like to pass to va_list 

} 

क्या किसी के पास कोई सुराग है कि मैं यह कैसे कर सकता हूं?

+1

आप 'foo' कार्यप्रणाली के साथ छेड़छाड़ कर सकते हैं? – adf88

+2

http://stackoverflow.com/questions/988290/populating-a-va-list – Hasturkun

+0

के संभावित डुप्लिकेट सही उत्तर के संदर्भ में निश्चित रूप से डुप्लिकेट करें। – bmargulies

उत्तर

0

यदि सूची में तत्वों की संख्या सीमित है, तो मैं तत्वों की संख्या के आधार पर मैन्युअल प्रेषण के लिए जाऊंगा।

void call_foo(int count, ...) { 
    va_list args; 
    va_start(args, count); 
    foo(count, args); 
    va_end(args); 
} 

switch (contacts.count()) { 
    case 0: return call_foo(contacts.count()); 
    case 1: return call_foo(contacts.count(), 
          contacts.at(0)->getName()); 
    case 2: return call_foo(contacts.count(), 
          contacts.at(0)->getName(), 
          contacts.at(1)->getName()); 
    case 3: return call_foo(contacts.count(), 
          contacts.at(0)->getName(), 
          contacts.at(1)->getName(), 
          contacts.at(2)->getName()); 
    default: /* ERROR HERE, ADD MORE CASES */ return call_foo(0); 
} 
+1

इसका कारण यह है कि ऐसा करने का सबसे प्रभावी तरीका यह नहीं है: मेरे पास 1-999 तत्व हो सकते हैं संपर्क और यह बहुत बदसूरत लगेगा। मैं बेहतर कुशल समाधान खोजने की उम्मीद कर रहा था। आरजीडीएस लुकाज़ – user404251

+0

मुझे यकीन नहीं है कि यह 999 पैरामीटर के साथ एक समारोह को कॉल करने के लिए * बेहतर-कुशल * है। –

+0

क्या आप वाकई लाइब्रेरी में foo फ़ंक्शन 999 पैरामीटर के साथ va_list को संभालने में सक्षम होंगे? –

0

यह कंपाइलर पर निर्भर करता है कि va_list प्रकार क्या है, va_start और va_end macros क्या हैं। आप इसे मानक तरीके से नहीं कर सकते हैं। आपको कंपाइलर-विशिष्ट निर्माण का उपयोग करना होगा।

शायद आप 'foo' फ़ंक्शन को बदल सकते हैं? यदि ऐसा है, तो इसे उलटा बनाओ - va_list को QList में परिवर्तित करें और 'foo' QList को स्वीकार करें।

// संपादित

तो क्या va_list प्रकार है देखते हैं, क्या va_start और va_end मैक्रो अपने विशिष्ट संकलक में हैं। फिर अपनी va_list को इस तरह से बनाएं कि ये मैक्रोज़ इस पर काम करेंगे।

+0

मैं वास्तव में इसकी उम्मीद कर सकता था। मैं विंडोज आईडीई के लिए क्यूटी ऐप विकसित करता हूं: विजुअल स्टूडियो 2005. – user404251

+0

मैं यह नहीं कर सकता, अगर यह कार्य LIB द्वारा खुलासा किया गया है :)। मेरे पास इसके लिए स्रोत कोड नहीं है। – user404251

+0

मैं यह नहीं कर सकता, यह वह कार्य है जो LIB द्वारा खुलासा किया गया है :)। मेरे पास इसके लिए स्रोत कोड नहीं है। – user404251

3

आपका प्रश्न सी ++ टैग किया गया है और सी ++ में पूरी तरह से varargs से बचने के लिए अच्छे तरीके (जैसे धाराएं) हैं।

यह एक महान उदाहरण है कि क्यों va_args दर्द का कारण बन सकता है। यदि आपके पास foo के हस्ताक्षर को बदलने का कोई मौका है, तो यह आपका सबसे अच्छा विकल्प है। Va_list के बजाय std::vector<std::string> लेना सिर्फ आपकी समस्या को हल करेगा।

यदि foo बाहरी पुस्तकालय में है तो आप नहीं बदल सकते हैं, मेरा अगला सुझाव एक अलग पुस्तकालय ढूंढना होगा।

यदि उनमें से कोई भी विकल्प नहीं है तो ऐसा लगता है कि va_list का उपयोग करके कॉल सूची को फिर से बनाने का एक तरीका होना चाहिए, लेकिन मुझे यह पता नहीं लगा कि यह काम कैसे किया जाए।

5

आप जो करना चाहते हैं वह कॉल स्टैक अनुकरण करना है ताकि आप foo() में एक निर्मित va_list पास कर सकें। यह संकलक के लिए विशिष्ट है (और चेतावनी, 32- और 64-बिट कंपाइलर्स के बीच अंतर भी हैं)। निम्नलिखित कोड मनोरंजन प्रयोजनों के लिए है !!! (यदि यह आपके सिस्टम पर भी काम करता है) तो यह टूटने का प्रवण है। इसके साथ में, मैं एक फ्लैट मेमोरी बफर का उपयोग करता हूं और इसे गिनती और चरित्र तारों का एक गुच्छा के साथ पॉप्युलेट करता हूं। आप इसे अपने तारों के लिए पॉइंटर्स के साथ उपयुक्त के रूप में भर सकते हैं और उन्हें नीचे सौंप सकते हैं।

यह केवल 32-बिट अनुप्रयोगों के लिए, मेरे सिस्टम, विंडोज 7 डब्ल्यू/विजुअल स्टूडियो 2008 पर काम करता प्रतीत होता है।

* बीएडी आईडीई कोड का पालन करें !!! *

#define PSEUDOSTACKSIZE (sizeof(int) + 999 * sizeof(const char*)) 
#pragma pack(push,1) 
union PSEUDOSTACK 
{ 
    int count; 
    char data[PSEUDOSTACKSIZE]; 
}; 
#pragma pack(pop) 

void foo(int count, va_list args) 
{ 
    for (int i = 0; i < count; i++) 
    { 
     char *s = va_arg(args, char*); 
     printf("%s\n", s); 
    } 
} 

void bar(PSEUDOSTACK data, ...) 
{ 
    va_list args; 
    va_start(args, data.count); 
    foo(data.count, args); 
    va_end(args); 
} 
// And later on, the actual test case code. 
PSEUDOSTACK barData; 
barData.count = 999; 
char *p = barData.data + sizeof(int); 
for (int i = 0; i < 999; i++, p += sizeof(char*)) 
{ 
    *reinterpret_cast<char**>(p) = "ThisIsABadIdea"; 
} 
bar(barData); 

मैं अब इस तरह के एक विचार के बारे में सोच के लिए शर्म की बात है में मेरे सिर लटका जायेंगे।

+0

न केवल खराब विचार, संभवतः यहां तक ​​कि विरोधाभासी सी मानक (सी 99: 7.15.1.1.2, 7.15.1.3.2 और संभवतः 7.15.1.4.2), संभवतः अपरिभाषित व्यवहार। वास्तव में यकीन नहीं है, यद्यपि। – Aconcagua

-1

सिर्फ मनोरंजन के >

  • मनमाना तर्क गिनती
  • सौभाग्य से sizeof (std :: wstring) अनुमति देने के लिए < sizeof की एक बहु (int)
  • W2K3 SP2 32 बिट + दृश्य ग पर परीक्षण किया है ++ 2010
 

#include <stdarg.h> 
#include <string> 
#include <vector> 
#include <iostream> 

#define N 6 // test argument count 

void foo(int n, ...); 

int main(int, char*[]) 
{ 
    std::vector strings; 
    std::wstring s(L"a"); 
    int i(0); 

    // create unique strings... 
    for (; i != N; ++i) 
    { 
     strings.push_back(s); 
     ++s.front(); 
    } 

    int n_stack_strings(N*sizeof(std::wstring)), // space needed for strings 
     n_stack(sizeof(int)+n_stack_strings); // overall stack space...needed for cleanup 

    __asm sub esp, n_stack_strings ; reserve stack space 

    std::wstring* p_stack(0); 

    __asm mov p_stack, esp ; get stack pointer 

    std::wstring* p(p_stack); 
    std::vector<std::wstring>::iterator string(strings.begin()); 

    // copy to stack 
    for (; string != strings.end(); ++string, ++p) 
     new (p) std::wstring(*string); 
    __asm push N ; argument count...arguments right to left (__cdecl) 
    __asm call foo 
    // cleanup 
    for (p = p_stack; p != p_stack+N; ++p) 
     p->~basic_string(); 
    __asm add esp, n_stack ; caller has to cleanup the stack (__cdecl) 
    return 0; 
} 

void foo(int n, ...) 
{ 
    int i(0); 
    va_list marker; 

    va_start(marker, n); 
    for (; i != n; ++i) 
     std::wcout << va_arg(marker, std::wstring) << std::endl; 
    va_end(marker); 
} 
 

</सिर्फ मनोरंजन के लिए >

3

... हममम ... शायद पोर्टेबल नहीं यकीन है कि अच्छा नहीं करने के लिए ... ... लेकिन समाधान हो सकता है yor समस्या ...

  • va_list (कम से कम दृश्य ग के लिए ++) है सिर्फ एक चार के लिए #define *
  • → तर्क
  • → कोडांतरक और/या प्रतिलिपि (उपयोग करने की आवश्यकता को देखने के अपने 'सिर्फ ढेर
  • → तर्क सिर्फ स्मृति में निरंतर होना भी आवश्यक है पर होने की जरूरत नहीं है मजेदार उत्तर के लिए ':-)
  • → सफाई के बारे में चिंता करने की आवश्यकता नहीं
  • कुशल!
  • W2K3 SP2 32 बिट + कुलपति पर परीक्षण ++ 2010
 

#include <stdarg.h> 
#include <string> 
#include <vector> 
#include <iostream> 

#define N 6 // test argument count 

void foo(int n, va_list args); 

int main(int, char*[]) 
{ 
    std::vector<std::wstring> strings; 
    std::wstring s(L"a"); 
    int i(0); 

    // create unique strings... 
    for (; i != N; ++i) 
    { 
     strings.push_back(s); 
     ++s.front(); 
    } 
    foo(N, reinterpret_cast<va_list>(strings.data())); 
    return 0; 
} 

void foo(int n, va_list args) 
{ 
    int i(0); 

    for (; i != n; ++i) 
     std::wcout << va_arg(args, std::wstring) << std::endl; 
} 
 
0

आप उपयोग करना क्या प्रयास कर रहे हैं alloca है। va_list ऑब्जेक्ट वेरिएबल्स को स्टोर नहीं कर सकता है, फ़ंक्शन कॉल उन्हें स्टोर करता है, और आप इसे केवल va_list के माध्यम से एक्सेस कर सकते हैं। ये चर केवल कॉल के दौरान मान्य हैं, और बाद में वे ovverwriten मिलता है।

इससे काम नहीं बनेगा:

va_list func(int dummy, ...) 
{ 
    va_list result; 
    va_start(result, dummy); 
    return result; 
} 

ढेर पर स्मृति को आबंटित करने के लिए एक variadic कार्यों alloca का उपयोग लिखने के बिना,। यह malloc की तरह कम या कम काम करता है, लेकिन आपको free पर कॉल करने की आवश्यकता नहीं है, जब आप स्कोप छोड़ते हैं तो यह स्वचालित रूप से मुक्त हो जाता है।

int * local = (int *) alloca(3 * sizeof(int)); 
local[0] = 10; 
local[1] = 20; 
local[2] = 30; 

यह मौलिक

int local[3]; 
local[0] = 10; 
local[1] = 20; 
local[2] = 30; 

लेकिन alloca 3 के साथ लेखन एक निरंतर होने की जरूरत नहीं है के रूप में ही है। फिर आप केवल इसे संलग्न क्षेत्र के अंदर उपयोग कर सकते हैं, इसलिए इसे फ़ंक्शन से वापस न करें।

यदि आप एक va_list से चाहते हैं एक सूची में कई प्रकार के इस तरह एक संघ लिखने पर विचार है:

union variant 
{ 
    int   i; 
    unsigned int u; 
    float  f; 
    double  d; 
    const char * s; 
    void *  v; 
}; 
संबंधित मुद्दे