2012-06-08 10 views
12

को देखते हुए की तरहनिर्दिष्ट 64-बिट संरेखण

struct foo { 
    int a, b, c; 
}; 

एक संरचना परिभाषा यह है कि यह हमेशा एक 64-बिट पता करने के लिए गठबंधन किया जाना चाहिए निर्दिष्ट करने के लिए सबसे अच्छा (सबसे सरल, सबसे विश्वसनीय और पोर्टेबल) तरीका है क्या, यहां तक ​​कि एक पर 32-बिट बिल्ड? मैं जीसीसी 4.5.2 के साथ सी ++ 11 का उपयोग कर रहा हूं, और क्लैंग का समर्थन करने की उम्मीद कर रहा हूं।

+0

मैं उत्सुक हूं; यह क्यों मायने रखता है कि 32-बिट सिस्टम पर संरेखण क्या है? या, वास्तव में, 64-बिट सिस्टम पर, क्योंकि उस संरचना को आमतौर पर 32-बिट से अधिक संरेखित होने की आवश्यकता नहीं होती है। –

+0

एक बार जब संकलक इसका समर्थन करते हैं, तो आप alignas का उपयोग कर सकते हैं। – PlasmaHH

+0

@ जोनाथनफिल्लर: मैं कुछ स्वचालित एसएस अनुकूलन के लिए अनुमति देना चाहूंगा। जीसीसी ने हाल ही में कुछ __builtin_assume_aligned को संकलक को बताने के लिए जोड़ा है कि सामान को गठबंधन होने की उम्मीद है। Http://gcc.godbolt.org/ उदाहरणों के साथ खेलना अधिक अंतर्दृष्टि दे सकता है। – PlasmaHH

उत्तर

14

जब से तुम कहते हैं कि तुम जीसीसी का उपयोग कर रहे हैं और उम्मीद कर बजना समर्थन करने के लिए, जीसीसी के alignedattribute चाल करना चाहिए:

struct foo { 
    int a, b, c; 
} __attribute__((__aligned__(8))); // aligned to 8-byte (64-bit) boundary 
+1

यह पोर्टेबल नहीं है। लेकिन फिर, कुछ भी नहीं होगा। –

+1

@ जॉन डीबलिंग: मुझे पता है। यह प्रश्न में दो कंपाइलर्स के लिए पोर्टेबल है। – Fanael

+0

यह आपके द्वारा लिंक किए गए दस्तावेज़ के अनुसार __attribute __ ((गठबंधन (8)) नहीं होना चाहिए? – D0SBoots

1

पोर्टेबल? मैं वास्तव में वास्तव में एक पोर्टेबल तरीके के बारे में नहीं जानता। जीसीसी में __attribute__((aligned(8))) है, और अन्य कंपाइलर्स में समकक्ष भी हो सकते हैं, जिन्हें आप प्रीप्रोसेसर निर्देशों का उपयोग करके पता लगा सकते हैं।

7

निम्नलिखित यथोचित पोर्टेबल, इस अर्थ में कि यह एक पर काम करेंगे है विभिन्न कार्यान्वयन की बहुत है, लेकिन सभी:

union foo { 
    struct {int a, b, c; } data; 
    double padding1; 
    long long padding2; 
}; 

static char assert_foo_size[sizeof(foo) % 8 == 0 ? 1 : -1]; 

संकलित करने के लिए असफल हो जायेगी कि जब तक या तो:

  • संकलक foo करने के लिए कुछ गद्दी जोड़ा गया है 8 की एक बहु है, जो आम तौर पर केवल एक संरेखण की आवश्यकता के कारण के लिए क्या होगा करने के लिए इसे लाने के लिए, या
  • foo.data के लेआउट अत्यंत अजीब बात है, या
  • एक long long और double 3 इंच से बड़ा है, और 8 का एक से अधिक है जिसका अर्थ यह नहीं है कि यह 8-गठबंधन है।

यह देखते हुए कि आपको केवल 2 कंपाइलर्स का समर्थन करने की आवश्यकता है, और क्लैंग डिजाइन द्वारा काफी जीसीसी-संगत है, बस काम करता है __attribute__ का उपयोग करें। केवल कुछ और करने का विचार करें यदि आप अब कोड लिखना चाहते हैं जो (उम्मीद है) उन कंपाइलरों पर काम करेगा जिन पर आप परीक्षण नहीं कर रहे हैं।

सी ++ 11 alignof जोड़ता है, जिसे आप आकार का परीक्षण करने के बजाय परीक्षण कर सकते हैं। यह झूठी सकारात्मकताओं को हटा देगा, लेकिन फिर भी आपको कुछ अनुरूप कार्यान्वयन के साथ छोड़ देगा जिस पर संघ आपके इच्छित संरेखण को बनाने में विफल रहता है, और इसलिए संकलन करने में विफल रहता है। इसके अलावा, मेरी sizeof चाल काफी सीमित है, यह आपकी सहायता नहीं करता है अगर आपकी संरचना में केवल 3 की बजाय 4 इंच हैं, जबकि alignof के साथ एक ही चीज़ है। मुझे नहीं पता कि जीसीसी और क्लैंग के कौन से संस्करण alignof का समर्थन करते हैं, यही कारण है कि मैंने इसे शुरू करने के लिए उपयोग नहीं किया। मैंने सोचा नहीं था कि करना मुश्किल है।

वैसे, अगर foo के उदाहरण गतिशील रूप से आवंटित किए जाते हैं तो चीजें आसान हो जाती हैं। सबसे पहले, मुझे संदेह है कि glibc या इसी तरह के malloc कार्यान्वयन 8-संरेखित होंगे - यदि 8-बाइट संरेखण के साथ मूल प्रकार है तो malloc है, और मुझे लगता है कि glibc malloc हमेशा चिंता करता है कि क्या है या नहीं, किसी भी दिए गए मंच पर नहीं। दूसरा, सुनिश्चित करने के लिए posix_memalign है।

+0

+1 बहुत अच्छा (बिना किसी गंदे कंपाइलर एक्सटेंशन के)। ओपी की मूल संरचना के समान व्यवहार पाने के लिए कोई भी 'डेटा' संरचना को अज्ञात बना सकता है। –

+0

प्लेटफार्मों/कंपाइलरों के निर्धारित सेट के लिए अच्छा समाधान। यदि सही पोर्टेबिलिटी आपका लक्ष्य है, तो धारावाहिक डेटा की बाइनरी संगतता शायद एक अतिरिक्त लक्ष्य नहीं होनी चाहिए। – cptstubing06

+0

क्यों डबल/लंबा लंबा ??? uint64_t को अधिक सुरक्षित रूप से उपयोग किया जा सकता है, इसके अतिरिक्त, पैडिंग को थोड़ा सा क्षेत्र उपयोग करके छुपाया जा सकता है: 'uint64_t: 0;' – Aconcagua

1

मुझे यकीन है कि जीसीसी 4.5.2 पुराना है कि यह मानक संस्करण का समर्थन नहीं करता है, लेकिन सी ++ 11 विशेष रूप से संरेखण - std::aligned_storage और std::aligned_union अन्य चीज़ों के साथ सौदा करने के लिए कुछ प्रकार जोड़ता है (देखें अधिक जानकारी के लिए §20.9.7.6)।

मुझे लगता है कि ऐसा करने का सबसे स्पष्ट तरीका aligned_storage (या TR1 के, यदि आपके पास है) के बूस्ट के कार्यान्वयन का उपयोग करना होगा। यदि आप यह नहीं चाहते हैं, तो भी मैं आपके अधिकांश कोड में मानक संस्करण का उपयोग करने के बारे में कड़ी मेहनत करूँगा, और अपने स्वयं के उपयोग के लिए केवल एक छोटा सा कार्यान्वयन लिखूंगा जब तक आप मानक को लागू करने वाले कंपाइलर को अपडेट न करें। पोर्टेबल कोड, हालांकि, अभी भी __declspec(align... या __attribute__(__aligned__, ... जैसे कुछ का उपयोग करता है, उससे थोड़ा अलग दिखाई देगा।

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

struct foo { 
    int a, b, c; 

    void *operator new(size_t, void *in) { return in; } 
}; 

int main() { 
    stdx::aligned_storage<sizeof(foo), 8>::type buf; 

    foo& f = *new (static_cast<void*>(&buf)) foo(); 

    int address = *reinterpret_cast<int *>(&f); 

    if (address & 0x3 != 0) 
     std::cout << "Failed.\n"; 

    f.~foo(); 

    return 0; 
} 
के

:

template <std::size_t Len, std::size_t Alignment> 
struct aligned_storage { 
    typedef struct { 
     __attribute__(__aligned__(Alignment)) unsigned char __data[Len]; 
    } type; 
}; 

एक त्वरित परीक्षण कार्यक्रम इस का उपयोग करने के लिए कैसे दिखाने के लिए:

क्या इसके लायक है के लिए, यहाँ aligned_storage के एक कार्यान्वयन पर एक त्वरित वार जीसीसी के __attribute__(__aligned__,... निर्देश के आधार पर बेशक, असली उपयोग में आप यहां दिखाए गए अधिकांश कुरूपता को लपेट/छुपाएंगे। यदि आप इसे इस तरह छोड़ देते हैं, तो सैद्धांतिक/भविष्य की पोर्टेबिलिटी की कीमत शायद अधिक है।

2

आपको __attribute__((aligned(8)) का उपयोग करना चाहिए। हालांकि, मुझे यह विवरण केवल यह सुनिश्चित करता है कि संरचना का आवंटित आकार 8 बाइट्स से अधिक है। यह सुनिश्चित नहीं करता है कि प्रारंभ पता एकाधिक है।

उदाहरण के लिए। मैं __attribute__((aligned(64)) का उपयोग करता हूं, मॉलोक 64 बिट लंबाई वाली संरचना लौटा सकता है जिसका प्रारंभ पता 0xed2030 है।

यदि आप प्रारंभ पता चाहते हैं तो गठबंधन किया गया है, तो आपको aligned_alloc: gcc aligned allocation का उपयोग करना चाहिए। aligned_alloc(64, sizeof(foo) 0xed2040 वापस आ जाएगा।