2014-10-05 8 views
9

के बारे में और अधिक समझना मैं सोच रहा था कि वृद्धि के दो रूपों के बीच अंतर है या नहीं। links में से कुछ कहते हैं कि i ++ तेज है कि i = i + 1;i ++ और i = i + 1

साथ ही व्यक्ति के रूप में मेरा अवलोकन असेंबली कोड के लिए भी समान है। कृपया छवि जांचें जहां i ++ और i = i + 1 - enter image description here

एक और link है जो कहता है कि यह पहले सच साबित होता था कि वृद्धि ऑपरेटर अतिरिक्त और असाइनमेंट से तेज़ था, लेकिन अब कंपाइलर्स I ++ अनुकूलित करते हैं और i = i + 1 वही।

क्या कोई आधिकारिक दस्तावेज/पेपर है जिसे हम पुष्टि कर सकते हैं कि वास्तव में क्या सही है? (मैं आम तौर पर क्रेडिट के साथ जाता हूं और स्टैक ओवरफ्लो पर किसी व्यक्ति के स्वीकार्य उत्तरों की संख्या देता हूं। मेरे द्वारा प्रदान किए गए लिंक पर ऐसी कोई चीज़ नहीं मिल सका)।

+0

यह वास्तव में पर निर्भर करता है है जिस तरह से संकलक इसे संभालता है। मुझे नहीं लगता कि इस व्यवहार का सुझाव देने वाला कोई आधिकारिक पत्र है। – iqstatic

+0

उच्च प्रदर्शन के लिए आपके 'लिंक' में कारण' एडीडी 'और' असाइनमेंट 'के दो चरण शामिल हैं। हां, 'असाइनमेंट' समय खपत हो सकता है लेकिन इस मामले में इससे कोई फर्क नहीं पड़ता क्योंकि 'i + 1' के साथ आवंटित चर को पहले से ही रजिस्टर में उपलब्ध है।तो, ['आवंटन लिखें '] (http://www.cs.iastate.edu/~prabhu/Tutorial/CACHE/interac.html) का परिणाम प्रदर्शन क्षति नहीं होता है। – DOOM

+0

मुझे लगता है कि अधिकांश कंपाइलर्स उन्हें समान बनाने के लिए अनुकूलित करेंगे, लेकिन कुछ निर्देश सेट में, वृद्धि परमाणु है लेकिन असाइनमेंट और अतिरिक्त में दो कॉल लगते हैं। – Novaterata

उत्तर

5

कोई आधिकारिक दस्तावेज नहीं है। सी स्पेक यह घोषित नहीं करता है कि i ++ i + 1 से तेज़ होना चाहिए, इसलिए कंपेलर/ऑप्टिमाइज़र जो भी पसंद करते हैं उन्हें करने के लिए स्वतंत्र होते हैं (और वे आसपास के कोड और अनुकूलन स्तर के आधार पर अलग-अलग विकल्प बना सकते हैं)।

मैं i ++ का उपयोग करता हूं क्योंकि मेरे लिए पढ़ने के लिए तेज़ है, कम वर्णों को गलत टाइप करने के लिए।

15

दरअसल, यदि आप सी ++ करते हैं, तो इसके बजाय ++i लिखने के लिए उपयोग करना बेहतर होता है। कारण सरल है: i++ एक प्रतिलिपि की आवश्यकता है।

a = ++i; // a is set to the result of i+1 
a = i++; // make a copy of i, compute i+1, save the copy of i in a 

अनुकूलन के बिना, विधानसभा कोड इस तरह दिखेगा:

a = ++i;       a = i++; 

MOV eax, (i)      MOV eax, (i) 
            PUSH eax 
ADD eax, 1       ADD eax, 1 
MOV (i), eax      MOV (i), eax 
            POP eax 
MOV (a), eax      MOV (a), eax 

अब, अनुकूलन के साथ, परिणाम सी में एक ही है जहां ++ ऑपरेटर केवल पूर्णांकों और संकेत करने के लिए लागू होता है।

++ और -- देखते हैं क्योंकि ज्यादातर प्रोसेसर एक INC और समय सी लिखा गया था पर एक DEC अनुदेश था। तो अगर आप एक सूचकांक रजिस्टर का उपयोग कर रहा है, इन निर्देशों का लागू किया जाएगा:

char a[256]; 
...init 'a' in some way... 
int sum =0; 
for(int i = 0; i < 100; ++i) 
{ 
    sum += a[i]; 
} 

यह एक सरल INC के साथ किया जा सकता है (6502) के रूप में:

LDA #00 
    LDY #00 
LOOP: 
    CLC 
    ADC ($80),Y 
    INY    <-- ++i or i++ 
    CPY #100 
    BCC LOOP 

नोट सी में हम है एक और संकेतन एक चर बढ़ाने के लिए:

01:

i += 1; 

यह व्यावहारिक है अगर आप 1 से अधिक से रजिस्टर बढ़ाने के लिए की जरूरत है

i += 3; 

या रजिस्टर हर बार दोगुना करने के लिए:

i += i; // (equivalent to i *= 2; or i <<= 1; in C++) 

प्रश्न: क्यों INC और DEC सभी 80x86 के साथ उपयोग नहीं किया जाता है?

ऐसा समय है जब ADD reg, 1 और SUB reg, 1 निर्देश INC reg और DEC reg से तेज़ थे।पुराने दिनों में, यह तेज़ था क्योंकि निर्देश छोटा था और हमारे पास कोई कैश नहीं था (या बहुत कम)। आज, या तो निर्देश शायद इसके बारे में है।

नीचे एक टिप्पणी, "सुस्ती" के लिए एक कारण से था FLAGS रजिस्टर:

Intel Optimization Reference, section 3.5.1.1 Use of the INC and DEC Instructions

एक और से

, अधिक वर्तमान टिप्पणी, यह सुस्ती कि इंटेल दस्तावेज़ में संदर्भित तय किया गया है की तरह लग रहा नए प्रोसेसर में। इसलिए इन निर्देशों का उपयोग या गैर-उपयोग लक्ष्य प्रोसेसर पर निर्भर होना चाहिए यदि अग्रिम में जाना जाता है।


के रूप में एक टिप्पणी में phresnel से कहा, i++ और ++i के बीच का अंतर शायद कई लोगों के लिए स्पष्ट नहीं था। एक पूर्णांक के लिए, अनुकूलन वास्तव में मामूली है और निश्चित रूप से -O0 के साथ भी होगा। हालांकि, सी ++ में, यह एक अलग कहानी है। दोनों वृद्धिशील ऑपरेटरों के साथ एक वर्ग है जो स्पष्ट रूप से दिखा रहा है कि i++ के लिए एक प्रति आवश्यक है (भले ही data_ केवल एक पूर्णांक है, हालांकि उस स्थिति में आप यह भी कर सकते हैं: return data_++ - इसे अभी भी एक अच्छी छिपी हुई प्रति की आवश्यकता है!):

class A 
{ 
public: 
    A& operator ++() // ++i -- no copy 
    { 
     ...apply the ++ operation to 'data_'... 
     return *this; // return a reference to this 
    } 

    A operator ++ (int) // i++ -- needs a temporary copy 
    { 
     // remember that the 'int' is totally ignored in the function, 
     // its only purpose is to distinguish '++i' from 'i++' 

     A copy = *this; // here we need a copy 
     ++*this; 
     return copy;  // and here we return said copy 
    } 

private: 
    some_type_t data_; 
}; 

ध्यान दें कि आधुनिक सी ++ compilers के रूप में दिए गए मान एक अतिरिक्त प्रति की आवश्यकता के बिना बाहर अनुकूलित किया जा सकता है i++ समारोह में दो प्रतियां नहीं बनाते हैं।

दोनों ही मामलों के बीच अंतर के रूप में दिखाया जा सकता है स्पष्ट रूप से धीमी i++ का उपयोग कर Is there a performance difference between i++ and ++i in C++? (लिंक phresnel ने उल्लेख किया) में वर्णित के रूप में अगर

+0

"सी में जहां ++ ऑपरेटर केवल पूर्णांक पर लागू होता है" - और पॉइंटर्स (और वास्तविक फ़्लोटिंग प्रकार)। आगे 'int sum (0);' और '(int i (0); ...) में C++ वाक्यविन्यास को छोड़ने का सुझाव दें। और अंतिम स्निपेट में समकक्ष भी सी के लिए पकड़ते हैं (दूसरा वाला केवल गैर-ऋणात्मक 'i' के बराबर है)। – mafso

+0

सभी स्पष्टीकरण के लिए @Alexix Wilke धन्यवाद। – Sagrian

+0

@ माफसो, मैंने सोचा कि फ्लोटिंग पॉइंट्स पर '++' और '--' की अनुमति नहीं थी। लेकिन वास्तव में, पॉइंटर्स उनका समर्थन करते हैं! तथ्य सी ++ में है, आप उन ऑपरेटरों को अधिभारित कर सकते हैं और यदि संभव हो तो बाएं तरफ डालते समय परिणाम बहुत तेज होते हैं। अब ... 'i * = 2'' i + = i' जैसा ही है, भले ही 'i' ऋणात्मक है। –

3
उन दोनों के बीच

Runthe कोड प्रोफाइलर यह और दोनों i ++ के लिए ही होगा मैं = मैं जीसीसी कंपाइलर के वर्तमान संस्करण के लिए +1। यह पूरी तरह से संकलक अनुकूलन पर निर्भर करता है।

आप प्रोसेसर के बारे में बात करते हैं जो विशेष तौर पर मशीन चक्र के लिए नीचे दिए गए चार्ट,

कांग्रेस देख सकते हैं - वृद्धि

Usage: INC  dest 
    Modifies flags: AF OF PF SF ZF 

    Adds one to destination unsigned binary operand. 

          Clocks     Size 
    Operands   808x 286 386 486   Bytes 

    reg8    3  2  2  1    2 
    reg16    3  2  2  1    1 
    reg32    3  2  2  1    1 
    mem    15+EA 7  6  3   2-4 (W88=23+EA) 

जोड़ें - अंकगणित अलावा

Usage: ADD  dest,src 
    Modifies flags: AF CF OF PF SF ZF 

    Adds "src" to "dest" and replacing the original contents of "dest". 
    Both operands are binary. 

          Clocks     Size 
    Operands   808x 286 386 486   Bytes 

    reg,reg   3  2  2  1    2 
    mem,reg   16+EA 7  7  3   2-4 (W88=24+EA) 
    reg,mem   9+EA 7  6  2   2-4 (W88=13+EA) 
    reg,immed   4  3  2  1   3-4 
    mem,immed  17+EA 7  7  3   3-6 (W88=23+EA) 
    accum,immed  4  3  2  1   2-3 

आप मशीन प्राप्त कर सकते हैं प्रत्येक निर्देश के लिए लिया गया चक्र एडीडी और विभिन्न प्रोसेसर, 8086, 80286, 80386, 80486, ऊपर के लिए आईएनसी, आप इसे इंटेल प्रोसेसर मैनुअल में दस्तावेज कर सकते हैं। मशीन चक्रों को प्रतिक्रिया को तेज़ी से कम करें।

+1

नीचे उल्लिखित उल्लेख के अनुसार, 'आईएनसी' और 'डीईसी 'आधुनिक प्रोसेसर पर धीमे हैं जो कई निर्देशों को पुनर्गठित करते हैं लेकिन उस पुनर्गठन में सीमित हैं जब कोई निर्देश CFLAGS में सभी झंडे को नहीं बदलता है। प्रोसेसर चलने से पहले निर्देश पाइपलाइन को काफी हद तक निकालना पड़ता है। ऐसा कहा जा रहा है कि ज्यादातर मामलों में गति वास्तव में समान होगी क्योंकि अनुकूलक कोड उत्पन्न करेगा जो दोनों मामलों में बिल्कुल समान है। –

-1

आरएमवी = 10;

RMV = RMV ++; // RMV +1 दोनों कर रहे हैं एक ही

printf ("1.time =% d", RMV);

// उत्पादन दूसरी बार वेतन वृद्धि की तुलना में 10, 10 + 1 इसलिए मूल्य is11

printf ("2.time =% d", RMV ++); // मूल्य 11

संबंधित मुद्दे