C ++ 0x में रूपांतरण को कम करना। क्या यह सिर्फ मेरे लिए है, या क्या यह ध्वनि एक टूटने वाले बदलाव की तरह है?


85

C ++ 0x निम्नलिखित कोड और इसी तरह के कोड को बीमार बनाने जा रहा है, क्योंकि इसमें एक से एक के तथाकथित संकीर्ण रूपांतरण की आवश्यकता होती doubleहै int

int a[] = { 1.0 };

मैं सोच रहा हूँ कि क्या इस तरह के इनिशियलाइज़ेशन का उपयोग वास्तविक विश्व कोड में ज्यादा किया जाता है। इस बदलाव से कितने कोड टूटेंगे? क्या आपके कोड में इसे ठीक करने का बहुत प्रयास किया जाता है, यदि आपका कोड बिल्कुल प्रभावित होता है?


संदर्भ के लिए, n3225 का 8.5.4 / 6 देखें

एक संकीर्ण रूपांतरण एक अंतर्निहित रूपांतरण है

  • एक फ्लोटिंग-पॉइंट प्रकार से एक पूर्णांक प्रकार, या
  • लंबे समय तक डबल से डबल या फ्लोट से, या डबल से फ्लोट तक, जहां स्रोत एक स्थिर अभिव्यक्ति है और रूपांतरण के बाद वास्तविक मूल्य उन मूल्यों की सीमा के भीतर है, जिनका प्रतिनिधित्व किया जा सकता है (भले ही यह बिल्कुल प्रतिनिधित्व नहीं किया जा सकता है), या
  • पूर्णांक प्रकार या अनकैप्ड एन्यूमरेशन प्रकार से ating ओटिंग-पॉइंट प्रकार तक, सिवाय इसके कि जहां स्रोत एक स्थिर अभिव्यक्ति है और रूपांतरण के बाद वास्तविक मान लक्ष्य प्रकार में फिट होगा और मूल प्रकार में वापस परिवर्तित होने पर मूल मान उत्पन्न करेगा, या
  • पूर्णांक प्रकार या अनकैप्ड एन्यूमरेशन प्रकार से पूर्णांक प्रकार जो मूल प्रकार के सभी मानों का प्रतिनिधित्व नहीं कर सकता है, सिवाय जहां स्रोत एक स्थिर अभिव्यक्ति है और रूपांतरण के बाद वास्तविक मान लक्ष्य प्रकार में फिट होगा और मूल मूल्य का उत्पादन करेगा जब मूल प्रकार में परिवर्तित।

1
यह मानते हुए कि यह केवल इनबिल्ट प्रकारों के आरंभ के लिए मान्य है, मैं यह नहीं देख सकता कि यह कैसे नुकसान पहुंचाएगा। ज़रूर, इससे कुछ कोड टूट सकते हैं। लेकिन ठीक करना आसान होना चाहिए।
जोहान कोटलिंस्की

1
@ जॉन डिबलिंग: नहीं, जब शुरुआती लक्ष्य प्रकार द्वारा मूल्य का प्रतिनिधित्व किया जा सकता है, तो इनिशियलाइज़ेशन बीमार नहीं है। (और 0पहले से ही intवैसे भी है।)
aschepler

2
@ नी: ध्यान दें कि यह केवल {घुंघराले ब्रेस इनिशियलाइज़र्स के भीतर ही बीमार है }, और उन की एकमात्र विरासत उपयोग सरणियों और पीओडी संरचनाओं के लिए है। इसके अलावा, यदि मौजूदा कोड में स्पष्ट जातियां हैं जहां वे हैं, तो यह टूटेगा नहीं।
22

4
@j_random_hacker जैसा कि वर्किंग पेपर कहता है, int a = 1.0;अभी भी मान्य है।
जोहान्स शाउब -

1
@litb: धन्यवाद। वास्तव में मुझे वह समझ में आता है लेकिन निराशाजनक - IMHO C ++ की शुरुआत से ही सभी संकीर्ण रूपांतरणों के लिए स्पष्ट वाक्यविन्यास की आवश्यकता होती है।
j_random_hacker

जवाबों:


41

मैं इस ब्रेकिंग बदलाव में भाग गया जब मैंने जीसीसी का इस्तेमाल किया। संकलक ने इस तरह कोड के लिए एक त्रुटि मुद्रित की:

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32};
}

समारोह में void foo(const long long unsigned int&):

त्रुटि: (((long long unsigned int)i) & 4294967295ull)से रूपांतरण को संकुचित करनाlong long unsigned intunsigned int अंदर करना {}

त्रुटि: अंदर (((long long unsigned int)i) >> 32)से रूपांतरण को संकुचितlong long unsigned int करना unsigned int{}

सौभाग्य से, त्रुटि संदेश सीधे थे और फिक्स सरल था:

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF),
            static_cast<unsigned int>(i >> 32)};
}

एक बाहरी पुस्तकालय में कोड एक फाइल में केवल दो घटनाओं के साथ था। मुझे नहीं लगता कि ब्रेकिंग चेंज ज्यादा कोड को प्रभावित करेगा। Novices हो सकता है मिल उलझन में, हालांकि।


9

मुझे यह जानकर आश्चर्य और निराशा होगी कि पिछले 12 वर्षों में मेरे द्वारा लिखे गए C ++ कोड में से किसी में भी इस तरह की समस्या थी। लेकिन अधिकांश कंपाइलरों ने किसी भी संकलन-समय "संकीर्णता" के बारे में चेतावनी दी होगी, जब तक कि मैं कुछ याद नहीं कर रहा हूं।

क्या ये भी रूपांतरण को कम कर रहे हैं?

unsigned short b[] = { -1, INT_MAX };

यदि ऐसा है, तो मुझे लगता है कि वे आपके फ़्लोटिंग-प्रकार से अभिन्न-प्रकार के उदाहरण से थोड़ा अधिक बार आ सकते हैं।


1
मुझे समझ नहीं आता कि आप यह क्यों कहते हैं कि यह कोड में खोजने के लिए एक असामान्य बात नहीं होगी। USHRT_MAX के बजाय -1 या INT_MAX का उपयोग करने के बीच तर्क क्या है? क्या USHRT_MAX 2010 के अंत में चढ़ाई में नहीं था?

7

अगर किसी को किसी चीज से पकड़ा जाता है तो मुझे आश्चर्य नहीं होगा:

float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};

(मेरे कार्यान्वयन पर, अंतिम दो उसी परिणाम का उत्पादन नहीं करते हैं जब वापस int / long में परिवर्तित हो जाते हैं, इसलिए संकुचित होते हैं)

मुझे याद नहीं है कि यह कभी भी लिखूं। यह केवल तभी उपयोगी होता है जब सीमाओं का सन्निकटन किसी चीज के लिए उपयोगी हो।

यह कम से कम अस्पष्ट भी लगता है:

void some_function(int val1, int val2) {
    float asfloat[] = {val1, val2};    // not in C++0x
    double asdouble[] = {val1, val2};  // not in C++0x
    int asint[] = {val1, val2};        // OK
    // now do something with the arrays
}

लेकिन यह पूरी तरह से आश्वस्त नहीं है, क्योंकि अगर मुझे पता है कि मेरे पास वास्तव में दो मूल्य हैं, तो उन्हें केवल के बजाय सरणियों में क्यों रखा जाए float floatval1 = val1, floatval1 = val2;? हालांकि, प्रेरणा क्या है, क्यों कि संकलन (और काम करना चाहिए, बशर्ते कि सटीकता का नुकसान कार्यक्रम के लिए स्वीकार्य सटीकता के भीतर हो), जबकिfloat asfloat[] = {val1, val2}; नहीं करना चाहिए? किसी भी तरह से मैं दो फ़ोटों से दो फ़्लोट्स को इनिशियलाइज़ कर रहा हूँ, यह सिर्फ एक मामले में दो फ़्लोट्स एक एग्रीगेट के सदस्य होने के लिए होता है।

उन मामलों में विशेष रूप से कठोर लगता है जहां एक गैर-स्थिर अभिव्यक्ति के परिणामस्वरूप एक संकीर्ण रूपांतरण होता है, भले ही (किसी विशेष कार्यान्वयन पर), स्रोत प्रकार के सभी मान गंतव्य प्रकार में प्रतिनिधित्व करने योग्य होते हैं और उनके मूल मूल्यों पर वापस परिवर्तनीय होते हैं:

char i = something();
static_assert(CHAR_BIT == 8);
double ra[] = {i}; // how is this worse than using a constant value?

यह मानते हुए कि कोई बग नहीं है, संभवतः रूपांतरण को स्पष्ट करने के लिए हमेशा फिक्स है। जब तक आप मैक्रोज़ के साथ कुछ अजीब नहीं कर रहे हैं, मुझे लगता है कि एक सरणी आरंभीकरण केवल सरणी के प्रकार के करीब दिखाई देता है, या कम से कम कुछ का प्रतिनिधित्व करने वाले प्रकार के लिए, जो एक टेम्पलेट पैरामीटर पर निर्भर हो सकता है। तो एक कास्ट आसान होना चाहिए, अगर क्रिया।


8
"अगर मुझे पता है कि मेरे पास दो मूल्य हैं, तो उन्हें सरणियों में क्यों रखा जाए" - उदाहरण के लिए क्योंकि ओपनजीएल जैसे एपीआई को इसकी आवश्यकता होती है।
जॉर्ज फ्रिट्ज़चे

7

एक व्यावहारिक उदाहरण जो मैंने सामना किया है:

float x = 4.2; // an input argument
float a[2] = {x-0.5, x+0.5};

सांख्यिक शाब्दिक अर्थ है doubleजो पदोन्नति का कारण बनता है।


1
इसलिए इसे floatलिखकर बनाएं 0.5f। ;)
अंडरस्कोर_ड

1
@underscore_d यह काम नहीं करता है यदि कोई टंकण floatया टेम्प्लेट पैरामीटर (कम से कम परिशुद्धता के नुकसान के बिना) था, लेकिन बिंदु यह है कि जैसा लिखा गया कोड सही शब्दार्थ के साथ काम करता है और सी ++ 11 के साथ एक त्रुटि बन गया। यानी, "ब्रेकिंग चेंज" की परिभाषा।
जद

5

उदाहरण के लिए, अपने CFLAGS को जोड़ने के लिए प्रयास करें:

CFLAGS += -std=c++0x -Wno-narrowing

या CP कंपाइलर्स के मामले में CPPFLAGS (बेशक यह आपके बिल्ड सिस्टम या आपके
मेकफाइल

4

रूपांतरण त्रुटि त्रुटियां अंतर्निहित पूर्णांक पदोन्नति नियमों के साथ बुरी तरह से मेल खाती हैं।

मेरे पास कोड के साथ एक त्रुटि थी जो दिखता था

struct char_t {
    char a;
}

void function(char c, char d) {
    char_t a = { c+d };
}

जो एक संकीर्ण रूपांतरण त्रुटि पैदा करता है (जो मानक के अनुसार सही है)। कारण यह है कि है cऔर dपरोक्ष करने के लिए प्रोत्साहित करने के intऔर जिसके परिणामस्वरूप intएक प्रारंभकर्ता सूची में चार को वापस संकुचित करने की अनुमति नहीं है।

OTOH

void function(char c, char d) {
    char a = c+d;
}

निश्चित रूप से अभी भी ठीक है (अन्यथा सभी नरक ढीले हो जाएंगे)। लेकिन हैरानी की बात तो यह भी है

template<char c, char d>
void function() {
    char_t a = { c+d };
}

ठीक है और चेतावनी के बिना संकलित करता है यदि c और d का योग CHAR_MAX से कम है। मुझे अभी भी लगता है कि यह C ++ 11 में एक दोष है, लेकिन वहां के लोग अन्यथा सोचते हैं - संभवतः क्योंकि बिना अंतर्निहित पूर्णांक रूपांतरण से छुटकारा पाना आसान नहीं है (जो कि अतीत से राहत है, जब लोगों ने कोड लिखा था जैसे char a=b*c/d(b * c)> CHAR_MAX) या रूपांतरण रूपांतरण त्रुटियों (जो संभवतः एक अच्छा विकल्प हैं) पर भी काम करने की अपेक्षा की गई है।


मैं निम्नलिखित में भाग गया जो वास्तव में कष्टप्रद बकवास है: unsigned char x; static unsigned char const m = 0x7f; ... unsigned char r = { x & m };<- अंदर रूपांतरण संकीर्ण {}। वास्तव में? तो ऑपरेटर और अंतर्निहित रूप से अहस्ताक्षरित चार्ट को भी धर्मान्तरित करता है? खैर मुझे परवाह नहीं है, परिणाम अभी भी अहस्ताक्षरित चार, argh होने की गारंटी है।
कार्लो वुड

" अंतर्निहित पूर्णांक रूपांतरण " पदोन्नति?
जिज्ञासु

2

यह वास्तव में एक ब्रेकिंग बदलाव था क्योंकि इस फीचर के साथ वास्तविक जीवन के अनुभव ने दिखाया है कि सी ++ 03 कोड बेस को C ++ 11 में पोर्ट करने के साथ वास्तविक जीवन के दर्द के कारण कई मामलों के लिए एक त्रुटि से चेतावनी में बदल गया है। इस टिप्पणी को एक जीसीसी बग रिपोर्ट में देखें :

मानक के लिए केवल यह आवश्यक है कि "एक अनुरूप कार्यान्वयन कम से कम एक निदान संदेश जारी करेगा" इसलिए कार्यक्रम को चेतावनी के साथ संकलित करने की अनुमति है। जैसा कि एंड्रयू ने कहा, -वेरर = संकीर्णता यदि आप चाहते हैं तो आपको इसे एक त्रुटि बनाने की अनुमति देता है।

G ++ 4.6 ने एक त्रुटि दी लेकिन इसे जानबूझकर 4.7 के लिए एक चेतावनी में बदल दिया गया क्योंकि बहुत से लोग (स्वयं शामिल थे) ने पाया कि संकीर्ण रूपांतरण जहां C ++ 11 के रूप में बड़े C ++ 03 कोडबेस को संकलित करने का प्रयास करते समय सबसे अधिक सामना करने वाली समस्याओं में से एक है । पहले अच्छी तरह से गठित कोड जैसे कि चार सी [] = {i, 0}; (जहां मैं केवल चार की सीमा के भीतर रहूंगा) त्रुटियों का कारण बना और उसे बदलकर चार सी में बदलना पड़ा [] = {(चार) मैं: 0}


1

ऐसा लगता है कि GCC-4.7 अब रूपांतरणों को कम करने के लिए त्रुटियां नहीं देता है, बल्कि इसके बजाय चेतावनी देता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.