2013-02-21 44 views
5

एक सी ++ विशिष्ट सवाल। इसलिए मैंने एक प्रोग्राम 32 बिट/64 बिट बनाने के बारे में एक प्रश्न पढ़ा है, और इसे प्राप्तकर्ता को ऐसा कुछ था (माफ करना, मुझे सवाल नहीं मिला, कुछ दिन पहले मैंने इसे देखा और मैं इसे फिर से नहीं ढूंढ पाया :(): जब तक आप कोई भी "सूचक धारणा" नहीं करते हैं, तो आपको केवल इसे पुन: संकलित करने की आवश्यकता होती है। इसलिए मेरा सवाल यह है कि पॉइंटर धारणाएं क्या हैं? मेरी समझ के लिए 32 बिट पॉइंटर और 64 बिट पॉइंटर्स हैं, इसलिए मुझे लगता है कि यह कुछ करना है कृपया। कोड के दौरान कोड में अंतर दिखाएं। कोड लिखते समय ध्यान में रखने के लिए किसी भी अन्य अच्छी आदतें, जो इसे बदलने के लिए आसान बनाने में मदद करती है :) भी कृपया उनके साथ उदाहरण साझा करेंकन्वर्टिबल कोड, 32 बिट/64 बिट कैसे लिखें?

Ps । मुझे पता है कि यह पोस्ट है: How do you write code that is both 32 bit and 64 bit compatible? लेकिन मुझे लगता है कि यह मेरे जैसे नए प्रोग्रामर के लिए कोई अच्छा उदाहरण नहीं है। एक 32 बिट भंडारण इकाई ect क्या है की तरह। किंडा इसे थोड़ा और तोड़ने के लिए hopping (कोई इरादा ^^) डीएस।

उत्तर

3

एक अच्छी तरह से गठित कार्यक्रम (यानी, सिंटैक्स के अनुसार लिखे गए एक प्रोग्राम और सी ++ के अर्थात् नियमों को बिना किसी अपरिभाषित व्यवहार के) लिखा गया है, सी ++ मानक गारंटी देता है कि आपके प्रोग्राम में देखने योग्य व्यवहारों का एक सेट होगा। अवलोकन करने योग्य व्यवहार आपके कार्यक्रम के भीतर अनिर्दिष्ट व्यवहार (कार्यान्वयन-परिभाषित व्यवहार सहित) के कारण भिन्न होते हैं। यदि आप अनिर्दिष्ट व्यवहार से बचते हैं या इसे हल करते हैं, तो आपके कार्यक्रम की एक विशिष्ट और निश्चित आउटपुट होने की गारंटी होगी। यदि आप इस तरह अपना प्रोग्राम लिखते हैं, तो आप 32-बिट या 64-बिट मशीन पर अपने प्रोग्राम के बीच कोई अंतर नहीं देखेंगे।

एक साधारण (मजबूर) एक कार्यक्रम विभिन्न संभावित आउटपुट होगा के उदाहरण इस प्रकार है:

int main() 
{ 
    std::cout << sizeof(void*) << std::endl; 
    return 0; 
} 

इस कार्यक्रम होगा संभावना 32- और 64-बिट मशीनों पर विभिन्न उत्पादन (नहीं लेकिन अनिवार्य रूप से)। sizeof(void*) का परिणाम कार्यान्वयन-परिभाषित है।

int main() 
{ 
    int size = sizeof(void*); 
    if (size != 4) { 
    size = 4; 
    } 
    std::cout << size << std::endl; 
    return 0; 
} 

इस कार्यक्रम हमेशा 4 बाहर प्रिंट होगा, इस तथ्य के बावजूद यह कार्यान्वयन से परिभाषित व्यवहार का उपयोग करता है: हालांकि, यह निश्चित रूप से एक प्रोग्राम है जो कार्यान्वयन से परिभाषित व्यवहार होता है, लेकिन अच्छी तरह से परिभाषित होने के लिए हल हो गई है संभव है। यह एक मूर्ख उदाहरण है क्योंकि हम अभी int size = 4; कर सकते थे, लेकिन ऐसे मामले हैं जब यह लेखन मंच-स्वतंत्र कोड में दिखाई देता है।

तो पोर्टेबल कोड लिखने का नियम है: अनिर्दिष्ट व्यवहार से बचने या हल करने का लक्ष्य

  1. कि जो सी ++ मानक निर्दिष्ट परे मौलिक प्रकार के आकार के बारे में कुछ भी यह मानकर न चलें:

    यहाँ अनिर्दिष्ट व्यवहार से बचने के लिए कुछ सुझाव हैं। यही है, char कम से कम 8 बिट है, short और int दोनों कम से कम 16 बिट्स हैं, और इसी तरह।

  2. सूचक जादू करने के लिए प्रयास न करें (पॉइंटर प्रकारों के बीच कास्टिंग या अभिन्न प्रकारों में पॉइंटर्स भंडारण)।

  3. एक unsigned char* का प्रयोग कर एक गैर char वस्तु (क्रमबद्धता या संबंधित कार्यों के लिए) का मूल्य प्रतिनिधित्व पढ़ने के लिए न करें।

  4. reinterpret_cast से बचें।

  5. करते समय सावधान रहें कार्य है कि अधिक या underflow हो सकता है प्रदर्शन। बिट-शिफ्ट ऑपरेशन करते समय ध्यान से सोचें।

  6. करते समय सावधान रहें सूचक प्रकार पर गणित कर रही है।

  7. void* प्रयोग न करें।

मानक में अनिर्दिष्ट या अपरिभाषित व्यवहार के कई और अधिक घटनाओं रहे हैं। उन्हें देखने के लायक है। some great articles ऑनलाइन हैं जो 32- और 64-बिट प्लेटफॉर्म के बीच अनुभव किए जाने वाले कुछ सामान्य अंतरों को कवर करते हैं। 32bit/64bit पोर्टिंग के लिए

+0

awsome anwser :) बस जो मैं देख रहा था :) –

+0

@FredrikBostonWestman तो आपको इसे स्वीकार करना चाहिए! – gsamaras

3

"सूचक धारणाएं" तब होती है जब आप कोड लिखते हैं जो अन्य डेटा प्रकारों में फिटिंग पर निर्भर करता है, उदा। int copy_of_pointer = ptr; - यदि int 32-बिट प्रकार है, तो यह कोड 64-बिट मशीनों पर टूट जाएगा, क्योंकि सूचक का केवल एक हिस्सा संग्रहीत किया जाएगा।

जब तक पॉइंटर्स केवल पॉइंटर प्रकारों में संग्रहीत होते हैं, तो यह कोई समस्या नहीं होनी चाहिए।

आमतौर पर, पॉइंटर्स "मशीन शब्द" का आकार होते हैं, इसलिए 32-बिट आर्किटेक्चर, 32 बिट्स और 64-बिट आर्किटेक्चर पर, सभी पॉइंटर्स 64-बिट होते हैं। हालांकि, कुछ वास्तुकलाएं हैं जहां यह सच नहीं है। मैंने कभी ऐसी मशीनों पर कभी काम नहीं किया है [x86 के अलावा इसके "दूर" और "नजदीकी" पॉइंटर्स के साथ - लेकिन अब इसे अनदेखा करते हैं]।

अधिकांश कंपाइलर आपको बताएंगे कि जब आप पॉइंटर को पूर्णांक में परिवर्तित नहीं करते हैं तो पॉइंटर फिट नहीं होता है, इसलिए यदि आप चेतावनियां सक्षम करते हैं, तो अधिकांश समस्याएं स्पष्ट हो जाएंगी - चेतावनियों को ठीक करें, और संभावनाएं बहुत अच्छी हैं कि आपका कोड सीधे काम करेंगे।

1

32 बिट कोड और 64 बिट कोड के बीच कोई अंतर नहीं होगा, सी/सी ++ का लक्ष्य और अन्य प्रोग्रामिंग भाषाएं असेंबली भाषा की बजाय उनकी पोर्टेबिलिटी हैं।

एकमात्र अंतर वह डिस्ट्रीब होगा जिसे आप अपना कोड संकलित करेंगे, सभी काम स्वचालित रूप से आपके कंपाइलर/लिंकर द्वारा किए जाते हैं, इसलिए बस इसके बारे में मत सोचें।

लेकिन: यदि आप एक 64 बिट distrib पर प्रोग्रामिंग कर रहे हैं, और आप उदाहरण एसडीएल के लिए एक बाहरी पुस्तकालय का उपयोग करने की जरूरत है, बाहरी पुस्तकालय अगर आप अपने कोड संकलन करना चाहते भी 64 बिट में संकलित किया जा करना होगा।

यह जानना एक बात यह है कि आपकी ईएलएफ फ़ाइल 32 बिट की तुलना में 64 बिट डिस्ट्रीब पर बड़ी होगी, यह सिर्फ तर्क है।

पॉइंटर के साथ क्या बिंदु है? जब आप एक सूचक को बढ़ाते/बदलते हैं, तो संकलक पॉइंटिंग प्रकार के आकार से आपके सूचक को बढ़ाएगा।

निहित प्रकार का आकार आपके प्रोसेसर के रजिस्टर आकार/आपके काम पर डिस्ट्रीब द्वारा परिभाषित किया गया है।

लेकिन आपको बस इसकी परवाह नहीं है, संकलन आपके लिए सबकुछ करेगा।

योग: यही कारण है कि आप 32 बिट डिस्ट्रीब पर 64 बिट ईएलएफ फ़ाइल निष्पादित नहीं कर सकते हैं।

+0

जब आप कहते हैं कि आप मुझे परेशान करते हैं? –

+1

@FredrikBostonWestman: यह उत्तर एक आधुनिक लिनक्स/बीएसडी-आधारित ऑपरेटिंग सिस्टम मानता है। ऐसे ओएस के "कार्यान्वयन" को वितरण कहा जाता है; वे एक स्थिर पूर्ण पैकेज के रूप में डिजाइन किए गए हैं जहां सब कुछ विशेष रूप से आर्किटेक्चर के लिए संकलित किया जाता है, यह चल रहा है। बंद स्रोत स्रोत के साथ इस तरह के लाभ प्राप्त करना मुश्किल है, जाहिर है ... – leftaroundabout

6

सामान्यतः इसका मतलब है कि आपका प्रोग्राम व्यवहार किसी भी प्रकार के sizeof() पर निर्भर नहीं होना चाहिए (जो कुछ सटीक आकार के नहीं होते हैं), न तो स्पष्ट रूप से और न ही निहित रूप से (इसमें संभावित संरचना संरेखण भी शामिल हैं)।

पॉइंटर्स केवल उनमें से एक सबसेट हैं, और शायद यह भी अर्थ है कि आपको असंबद्ध सूचक प्रकार और/या पूर्णांक के बीच रूपांतरित करने में सक्षम होने पर भरोसा करने की कोशिश नहीं करनी चाहिए, जब तक कि वे विशेष रूप से इस के लिए बने नहीं हैं (उदा। intptr_t)।

उसी तरह आपको डिस्क पर लिखी गई चीज़ों का ख्याल रखने की आवश्यकता है, जहां आपको कभी भी आकार के आकार पर भरोसा नहीं करना चाहिए प्रकारों में बनाया गया, हर जगह एक जैसा है।

जब भी आपको (बाहरी डेटा प्रारूपों के कारण) स्पष्ट रूप से आकार के प्रकार uint32_t का उपयोग करना है।

1

ठेठ नुकसान कर रहे हैं:

प्रोग्रामर कि sizeof (शून्य *) == 4 * sizeof (चार) द्वारा निहित धारणा। यदि आप यह धारणा बना रहे हैं और उदा। उस तरह से सरणी आवंटित करें ("मुझे 20 पॉइंटर्स चाहिए इसलिए मैं 80 बाइट आवंटित करता हूं"), आपका कोड 64 बिट पर टूट जाता है क्योंकि इससे बफर ओवररन्स हो जाता है।

"बिल्ली का बच्चा-हत्यारा", int x = (int) और कुछ; (और रिवर्स, शून्य * पीआरटी = (शून्य *) some_int)। फिर आकार (int) == आकार (शून्य *) की धारणा। इससे अतिप्रवाह नहीं होता है लेकिन डेटा खो देता है - पॉइंटर का उच्च 32 बिट, अर्थात्।

इन दोनों मुद्दों में एक प्रकार का वर्ग है जिसे टाइप एलियासिंग कहा जाता है (दो प्रकार के बीच बाइनरी प्रतिनिधित्व स्तर पर पहचान/इंटरचेंजबिलिटी/समकक्ष मानते हुए), और ऐसी धारणाएं आम हैं; की तरह संयुक्त राष्ट्र * एक्स पर, टाइम_टी, size_t, यह मानते हुए पूर्णांक किया जा रहा off_t, या Windows पर, संभालना, शून्य * और लंबे समय से किया जा रहा है विनिमेय, आदि ...

डेटा संरचना/ढेर स्थान उपयोग के बारे में अनुमान (नीचे 5. के रूप में देखें कुंआ)। सी/सी ++ कोड में, स्थानीय वैरिएबल को स्टैक पर आवंटित किया जाता है, और नीचे दी गई जगह के कारण 32 बिट और 64 बिट मोड के बीच उपयोग की गई जगह अलग होती है, और तर्क पारित करने के लिए अलग-अलग नियमों के कारण (32 बिट x86 आमतौर पर ढेर पर, 64 बिट रजिस्टरों में भाग में x86)। कोड जो कि 32 बिट पर डिफ़ॉल्ट स्टैक्सइज़ के साथ दूर हो जाता है, 64 बिट पर स्टैक ओवरफ़्लो क्रैश का कारण बन सकता है। क्रैश के कारण के रूप में यह अपेक्षाकृत आसान है लेकिन संभवतः ठीक करने के लिए एप्लिकेशन की कॉन्फ़िगर करने योग्यता के आधार पर।

32 बिट और 64 बिट कोड (विभिन्न कोड आकार/कैश पैरों के निशान, या विभिन्न मेमोरी एक्सेस विशेषताओं/पैटर्न, या विभिन्न कॉलिंग सम्मेलनों के कारण) के बीच अंतर अंतर "calibrations" तोड़ सकता है। कहें, के लिए (int i = 0; i < 1000000; ++ i) नींद (0); , एबीआई (अनुप्रयोग बाइनरी इंटरफ़ेस) होने की संभावना अंत में 32bit और 64bit के लिए अलग अलग समय के लिए ...

जा रहा है। आम तौर पर संकेत के आकार ... की तुलना में 64 बिट और 32 बिट वातावरण के बीच बड़ा मतभेद है वर्तमान में, दो मुख्य 64 बिट वातावरण के "शाखाओं" मौजूद हैं, IL32P64 (क्या Win64 का उपयोग करता है - पूर्णांक और लंबे समय से कर रहे हैं int32_t, केवल uintptr_t/शून्य * uint64_t है, से आकार के पूर्णांक के संदर्भ में बात करते हैं) और एलपी 64 (जो यूएन * एक्स का उपयोग करता है - int int32_t है, int int64_t है और uintptr_t/void * uint64_t है), लेकिन अलग-अलग संरेखण नियमों के "उपखंड" भी हैं - कुछ वातावरण मानते हैं अपने संबंधित आकारों पर लंबे, फ्लोट या डबल संरेखित करें, जबकि अन्य मानते हैं कि वे चार बाइट्स के गुणकों पर संरेखित हैं। 32 बिट लिनक्स में, वे सभी चार बाइट्स पर संरेखित करते हैं, जबकि 64 बिट लिनक्स में, फ्लोट आठ-बाइट गुणक पर चार, लंबे और डबल पर संरेखित होते हैं। इन नियमों का नतीजा यह है कि कई मामलों में, बिथ आकार (संरचना {...}) और संरचना/कक्षा के सदस्यों का ऑफसेट 32 बिट और 64 बिट वातावरण के बीच अलग है, भले ही डेटा प्रकार की घोषणा पूरी तरह से समान हो। सरणी/वेक्टर आवंटन को प्रभावित करने से परे, ये समस्याएं डेटा/आउटपुट में डेटा को भी प्रभावित करती हैं। फाइलों के माध्यम से - यदि एक 32 बिट ऐप लिखता है उदा। संरचना {चार ए; int बी; चार सी, लंबे डी; डबल ई} एक फ़ाइल में जो उसी ऐप को 64 बिट पढ़ने के लिए पुन: संकलित करता है, नतीजा यह नहीं होगा कि इसके लिए क्या उम्मीद की जा रही है। केवल दिए गए उदाहरण केवल भाषा प्राइमेटिव्स (char, int, long आदि) के बारे में हैं, लेकिन निश्चित रूप से सभी प्रकार के प्लेटफॉर्म-निर्भर/रनटाइम लाइब्रेरी डेटा प्रकारों को प्रभावित करते हैं, चाहे आकार_टी, ऑफ_टी, टाइम_टी, हैंडल, अनिवार्य रूप से कोई भी नॉनट्रिविअल स्ट्रक्चर/यूनियन/वर्ग ... - इसलिए यहां त्रुटि के लिए जगह बड़ी है,

और फिर निचले स्तर के मतभेद हैं, जो खेल में आते हैं जैसे हाथ से अनुकूलित असेंबली (एसएसई/एसएसई 2/...) के लिए; 32 बिट और 64 बिट में अलग-अलग (संख्याओं) रजिस्ट्रार हैं, नियमों को पार करने के विभिन्न तर्क; यह सब दृढ़ता से प्रभावित करता है कि इस तरह के अनुकूलन कैसे प्रदर्शन करते हैं और यह बहुत संभावना है कि उदा। एसएसई 2 कोड जो 32 बिट मोड में सर्वश्रेष्ठ प्रदर्शन देता है उसे सर्वश्रेष्ठ प्रदर्शन 64 बिट मोड देने के लिए पुनः लिखने/बढ़ाने की आवश्यकता होगी।

कोड डिज़ाइन बाधाएं भी हैं जो 32 बिट और 64 बिट के लिए बहुत अलग हैं, खासकर स्मृति आवंटन/प्रबंधन के आसपास; एक आवेदन जिसे सावधानीपूर्वक "32 बिट में प्राप्त किए जा सकने वाले मेम से नरक को अधिकतम करने" के लिए कोड किया गया है, इसमें जटिल तर्क होगा कि कैसे/कब आवंटित/मुक्त मेमोरी, मेमोरी-मैप किए गए फ़ाइल उपयोग, आंतरिक कैशिंग आदि - जिनमें से अधिकतर 64 बिट में हानिकारक हो जहां आप "उपलब्ध" विशाल उपलब्ध पता स्थान का लाभ उठा सकते हैं। ऐसा ऐप 64 बिट के लिए ठीक से पुनः संकलित हो सकता है, लेकिन कुछ "प्राचीन सरल बहिष्कृत संस्करण" से भी बदतर हो सकता है जिसमें अधिकतम अधिकतम-32 बिट पेफोल ऑप्टिमाइज़ेशन नहीं थे।

तो, आखिरकार, यह संवर्द्धन/लाभ के बारे में भी है, और जहां कहीं अधिक काम, आंशिक रूप से प्रोग्रामिंग में, आंशिक रूप से डिजाइन/आवश्यकताओं में आता है। भले ही आपका ऐप 32 बिट और 64 बिट वातावरण दोनों पर साफ-सुथरा हो और दोनों पर सत्यापित हो , क्या यह वास्तव में 64 बिट से लाभान्वित है? क्या 64 बिट में इसे और अधिक तेज़ी से चलाने के लिए कोड तर्क में किए जा सकते हैं? क्या आप 32 बिट पिछड़े संगतता को तोड़ने के बिना उन परिवर्तनों को कर सकते हैं? 32 बिट लक्ष्य पर नकारात्मक प्रभाव के बिना? वृद्धि कहाँ होगी, और आप कितना लाभ प्राप्त कर सकते हैं? एक बड़ी वाणिज्यिक परियोजना के लिए, इन सवालों के जवाब अक्सर रोडमैप पर महत्वपूर्ण मार्कर हैं क्योंकि आपका शुरुआती बिंदु कुछ मौजूदा "मनी मेकर" है ...

+1

http://www.viva64.com/en/a/0004/ पर देखने के योग्य – Saqlain