2011-09-14 12 views
7

6.7.2.1 C99 मानक के अपने मसौदे के अनुच्छेद 14 इस (, हमेशा की तरह, अतिरिक्त बल) यूनियनों और संकेत के बारे में कहना है:क्या हम यूनियनों के साथ va_arg का उपयोग कर सकते हैं?

The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.

सभी अच्छी तरह से और अच्छे

, इसका मतलब है कि यह कानूनी है

union ints { int i; unsigned u; }; 

int i = 4; 
union ints is = *(union ints *)&i; 
int j = is.i; // legal 
unsigned k = is.u; // not so much 

7.15.1.1 पैरा 2 इस कहना है::

की तरह एक संघ में या तो एक हस्ताक्षरित या अहस्ताक्षरित int कॉपी करने के लिए निम्नलिखित, यह मानते हुए कि हम केवल एक ही प्रकार के डेटा में इसे बाहर की प्रतिलिपि बनाना चाहते कुछ करना

The va_arg macro expands to an expression that has the specified type and the value of the next argument in the call. The parameter ap shall have been initialized by the va_start or va_copy macro (without an intervening invocation of the va_end macro for the sameap). Each invocation of the va_arg macro modifies ap so that the values of successive arguments are returned in turn. The parameter type shall be a type name specified such that the type of a pointer to an object that has the specified type can be obtained simply by postfixing a * to type . If there is no actual next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:

—one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;

—one type is pointer to void and the other is a pointer to a character type.

मैं जाने के लिए नहीं जा रहा हूं और डिफ़ॉल्ट तर्क प्रचार के बारे में हिस्सा उद्धृत नहीं कर रहा हूं। मेरा प्रश्न है:

void func(int i, ...) 
{ 
    va_list arg; 
    va_start(arg, i); 
    union ints is = va_arg(arg, union ints); 
    va_end(arg); 
} 

int main(void) 
{ 
    func(0, 1); 
    return 0; 
} 

यदि हां, तो यह एक साफ चाल पर काबू पाने में प्रवेश किया हुआ/अहस्ताक्षरित पूर्णांक रूपांतरण की आवश्यकता "और मूल्य दोनों प्रकार के साथ संगत है" (हालांकि प्रतीत होता: इस परिभाषित व्यवहार है एक तरीका है जो कानूनी रूप से कुछ भी करना मुश्किल है)। यदि नहीं, तो यह इस मामले में केवल unsigned का उपयोग करने के लिए सुरक्षित प्रतीत होता है, लेकिन यदि union में अधिक असंगत प्रकारों के साथ अधिक तत्व थे तो क्या होगा? अगर हम गारंटी दे सकते हैं कि हम तत्व द्वारा यूनियन तक नहीं पहुंचेंगे (यानी हम इसे किसी अन्य union या स्टोरेज स्पेस में कॉपी करते हैं जिसे हम union जैसे इलाज कर रहे हैं) और यह कि संघ के सभी तत्व समान आकार हैं, क्या यह अनुमति है varargs के साथ? या यह केवल पॉइंटर्स के साथ अनुमति दी जाएगी?

प्रैक्टिस में मुझे उम्मीद है कि यह कोड लगभग कभी असफल नहीं होगा, लेकिन मैं जानना चाहता हूं कि यह परिभाषित व्यवहार है या नहीं। मेरा वर्तमान अनुमान यह है कि ऐसा परिभाषित नहीं किया गया है, लेकिन यह अविश्वसनीय रूप से गूंगा लगता है।

+1

अब जब मैं इसके बारे में सोचता हूं, मुझे लगता है कि मुझे 'func (0, -1) में अधिक रुचि है; func (0, UINT_MAX); 'कानूनी है। 'func (0, 1)' कानूनी रूप से कानूनी हो सकता है क्योंकि 1 'int' और 'unsigned' दोनों में फिट बैठता है। –

+0

'हस्ताक्षरित k = is.u;' सी 99 में कानूनी है। –

+0

@Dietrich - क्या हस्ताक्षरित/हस्ताक्षरित चीज़ के कारण कोई अपवाद है? –

उत्तर

0

मुझे नहीं लगता कि आपको लगता है कि कोड अभ्यास में कभी विफल नहीं होना चाहिए। यह किसी भी कार्यान्वयन पर असफल हो जाएगा जहां पूर्णांक प्रकार पंजीकृत होते हैं लेकिन कुल प्रकार (यहां तक ​​कि जब छोटे) स्टैक पर पारित होते हैं, और मुझे मानक में कुछ भी नहीं दिखाई देता है जो इस तरह के कार्यान्वयन को रोकता है। एक int युक्त एक संघ int के साथ संगत प्रकार नहीं है, भले ही उनके आकार समान हों।

अपना पहला कोड टुकड़ा वापस, यह भी एक समस्या है:

union ints is = *(union ints *)&i; 

यह एक अलियासिंग उल्लंघन है और अपरिभाषित व्यवहार का आह्वान। आप memcpy का उपयोग करके इसे से बचने कर सकते हैं और मैं तो लगता है यह कानूनी होगा ..

मैं भी थोड़ा यहाँ अपनी टिप्पणी के बारे में उलझन में हूँ:

unsigned k = is.u; // not so much 

के बाद से मूल्य 4 में दोनों पर हस्ताक्षर किए प्रतिनिधित्व किया है और हस्ताक्षरित प्रकार, यह कानूनी होना चाहिए, जब तक कि इसे विशेष रूप से विशेष मामले के रूप में प्रतिबंधित नहीं किया जाता है।

यदि यह आपके प्रश्न का उत्तर नहीं देता है, तो शायद आप जो भी (सैद्धांतिक) समस्या को हल करने की कोशिश कर रहे हैं, उस पर अधिक विस्तृत जानकारी दे सकते हैं।

+0

क्या आप विस्तार कर सकते हैं कि यह एक अलियासिंग उल्लंघन कैसे है? – wnoise

+0

आप पहले 'int' प्रकार के प्रकार के माध्यम से ऑब्जेक्ट को' यूनियन इनट्स 'के माध्यम से एक्सेस करते हैं। संकलक मान सकता है कि वे एक-दूसरे को उपनाम नहीं करते हैं। –

+0

क्या कंपाइलर को इलिप्सिस ('...') के स्थान पर पारित पैरामीटर पर 'प्रतिबंध' मानने की अनुमति है। –

3

आपके पास कुछ चीजें हैं।

A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.

इसका मतलब यह नहीं है कि प्रकार संगत हैं। वास्तव में, वे संगत नहीं हैं।तो निम्न कोड गलत है:

func(0, 1); // undefined behavior 

आप एक संघ पारित करने के लिए चाहते हैं,

func(0, (union ints){ .u = BLAH }); 

आप कोड लिख कर जांच कर सकते हैं,

union ints x; 
x = 1; 

जीसीसी एक "त्रुटि दिखाता है: संकलन करते समय संदेश "असाइनमेंट में असंगत प्रकार" संदेश।

हालांकि, अधिकांश कार्यान्वयन "शायद" दोनों मामलों में सही काम करेंगे। कुछ अन्य समस्याओं ... हैं

union ints { 
    int i; 
    unsigned u; 
}; 

int i = 4; 
union ints is = *(union ints *)&i; // Invalid 
int j = is.i; // legal 
unsigned k = is.u; // also legal (see note) 

व्यवहार जब आप भिन्नता एक प्रकार अपनी वास्तविक प्रकार *(uinon ints *)&i के अलावा अन्य का उपयोग कर एक प्रकार का पता कभी कभी अपरिभाषित है (संदर्भ को देख, लेकिन मैं बहुत यकीन है कि के बारे में इस)। हालांकि, सी 99 में इसे हाल ही में संग्रहीत संघ के सदस्य (या यह सी 1 एक्स?) के अलावा किसी यूनियन सदस्य तक पहुंचने की अनुमति है, लेकिन मूल्य कार्यान्वित किया गया है और यह एक जाल प्रतिनिधित्व हो सकता है।

बारे में यूनियनों के माध्यम से प्रकार punning: पास्कल Cuoq नोटों के रूप में, यह वास्तव में TC3 कि सबसे हाल ही में एक संग्रहीत के अलावा किसी अन्य संघ तत्व तक पहुँचने का व्यवहार को परिभाषित करता है। सीसी के लिए टीसी 3 तीसरा अपडेट है। अच्छी खबर यह है कि टीसी 3 का यह हिस्सा वास्तव में मौजूदा अभ्यास को संहिताबद्ध कर रहा है - इसलिए इसे टीसी 3 से पहले सी के वास्तविक तथ्य के रूप में सोचें।

+3

टीसी 3 यह स्पष्ट करता है कि यूनियनों का उपयोग सी 99 में दंडित करने के लिए किया जा सकता है: दोष रिपोर्ट 283 http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm –

+0

@ पास्कल: अच्छा जानना! –

2

के बाद से मानक का कहना है:

The parameter type shall be a type name specified such that the type of a pointer to an object that has the specified type can be obtained simply by postfixing a * to type.

union ints के लिए, उस स्थिति को संतुष्ट है। चूंकि union ints *union ints पर पॉइंटर का एक पूर्ण रूप से अच्छा प्रतिनिधित्व है, इसलिए उस वाक्य में कुछ भी नहीं है जिससे इसे यूनियन के रूप में स्टैक पर धक्का दिया गया मूल्य एकत्र करने के लिए उपयोग किया जा सके।

यदि आप धोखा देते हैं और यूनियन के स्थान पर एक सादा int या unsigned int पास करने का प्रयास करते हैं, तो आप अपरिभाषित व्यवहार का आह्वान करेंगे। इस प्रकार, आप इस्तेमाल कर सकते हैं:

union ints u1 = ...; 

func(0, (union ints) { .i = 0 }); 
func(1, (union ints) { .u = UINT_MAX }); 
func(2, u1); 

आप उपयोग नहीं कर सका:

func(1, 0); 

तर्क संघ प्रकार नहीं कर रहे हैं।