2009-05-08 8 views
84

मैं निम्नलिखित कोड है:क्या GCC __attribute __ ((गठबंधन (x)) द्वारा गठित स्टैक चर हैं?)?

#include <stdio.h> 

int 
main(void) 
{ 
     float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0}; 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

और मैं निम्नलिखित उत्पादन:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

क्यों a[0] का पता 0x1000 की एक बहु नहीं है?

क्या वास्तव में __attribute__((aligned(x))) करता है? मैंने this स्पष्टीकरण गलत समझा?

मैं जीसीसी 4.1.2 का उपयोग कर रहा हूं।

उत्तर

94

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

इस कोड के साथ

:

#include <stdio.h> 

float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0}; 

int 
main(void) 
{ 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

मैं इस मिल:

0x804c000 0x804c004 0x804c008 0x804c00c 

जो क्या उम्मीद कर रहा है। आपके मूल कोड के साथ, मुझे बस आपके जैसे यादृच्छिक मान मिलते हैं।

+11

+1 सही उत्तर। स्थानीय सरणी स्थिर बनाने के लिए एक वैकल्पिक समाधान है। ढेर पर संरेखण हमेशा एक समस्या है और इसे टालने की आदत में जाना सर्वोत्तम है। –

+0

ओह हाँ, मैंने इसे स्थिर बनाने के बारे में नहीं सोचा था। यह एक अच्छा विचार है क्योंकि यह नाम टकराव को रोकता है। मैं अपना जवाब संपादित करूंगा। – Zifre

+2

ध्यान दें कि इसे स्थैतिक बनाना भी इसे गैर-पुनर्वित्तक और गैर-थ्रेड-सुरक्षित बनाता है। – ArchaeaSoftware

9

Alignement सभी प्रकार के लिए प्रभावी नहीं है। तुम एक संरचना का उपयोग कार्रवाई में विशेषताओं को देखने के लिए विचार करना चाहिए:

#include <stdio.h> 

struct my_float { 
     float number; 
} __attribute__((aligned(0x1000))); 

struct my_float a[4] = { {1.0}, {2.0}, {3.0}, {4.0} }; 

int 
main(void) 
{ 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

और फिर, आप पढ़ेंगे:

0x603000 0x604000 0x605000 0x606000 

कौन सा है कि तुम क्या उम्मीद कर रहे थे।

संपादित करें: @yzap और निम्नलिखित @Caleb प्रकरण टिप्पणी से पुश किया, प्रारंभिक समस्या जीसीसी संस्करण केवल के कारण है। मैं निवेदक के स्रोत कोड के साथ जीसीसी 3.4.6 पर देख लिया है जीसीसी 4.4.1 बनाम:

$ ./test_orig-3.4.6 
0x7fffe217d200 0x7fffe217d204 0x7fffe217d208 0x7fffe217d20c 
$ ./test_orig-4.4.1 
0x7fff81db9000 0x7fff81db9004 0x7fff81db9008 0x7fff81db900c 

यह है कि पुराने जीसीसी संस्करणों (कहीं 4.4.1 से पहले) संरेखण विकृतियों से पता चलता अब स्पष्ट है।

नोट 1: मेरा प्रस्तावित कोड सवाल जो मैं "सरणी के प्रत्येक क्षेत्र संरेखित" के रूप में समझा उत्तर नहीं देता।

नोट 2: गैर-स्थैतिक [] के अंदर मुख्य() और जीसीसी 3.4.6 के साथ संकलन करना स्ट्रक्चर की सरणी के संरेखण निर्देश को तोड़ता है लेकिन structs के बीच 0x1000 दूरी रखता है ... अभी भी बुरा! (समाधान के लिए @zifre उत्तर देखें)

+1

जैसा कि ज़िफ़्रे द्वारा उत्तर दिया गया है, यह प्रकार नहीं है, लेकिन तथ्य यह है कि आपने इसे अपने संस्करण में स्थिर बना दिया है। – ysap

+0

@ysap, यह दोनों जीसीसी संस्करण और वैश्विक परिभाषा थी जिसने इसे काम किया। टिप्पणी के लिए धन्यवाद! मैंने इसे ठीक करने के लिए जवाब संपादित किया। :) – levif

13

हाल जीसीसी (4.5.2-8ubuntu4 के साथ परीक्षण) सरणी ठीक से संरेखित साथ अपेक्षा के अनुरूप काम करने के लिए दिखाई देते हैं।

#include <stdio.h> 

int main(void) 
{ 
    float a[4] = { 1.0, 2.0, 3.0, 4.0 }; 
    float b[4] __attribute__((aligned(0x1000))) = { 1.0, 2.0, 3.0, 4.0 }; 
    float c[4] __attribute__((aligned(0x10000))) = { 1.0, 2.0, 3.0, 4.0 }; 

    printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
    printf("%p %p %p %p\n", &b[0], &b[1], &b[2], &b[3]); 
    printf("%p %p %p %p\n", &c[0], &c[1], &c[2], &c[3]); 
} 

मैं:

0x7ffffffefff0 0x7ffffffefff4 0x7ffffffefff8 0x7ffffffefffc 
0x7ffffffef000 0x7ffffffef004 0x7ffffffef008 0x7ffffffef00c 
0x7ffffffe0000 0x7ffffffe0004 0x7ffffffe0008 0x7ffffffe000c 
+0

यह थोड़ा आश्चर्यजनक है, मानकों को ढेर में आवंटित करने पर विचार करना - क्या इसका मतलब यह है कि ढेर अब छेद से भरा हुआ है? – ysap

+0

या उसका ढेर 16-बाइट गठबंधन है। – user7116

38

जीसीसी में एक बग कि विशेषता ढेर चर के साथ काम नहीं करने के लिए गठबंधन की वजह से हुई थी। यह नीचे जुड़े पैच के साथ तय किया गया प्रतीत होता है। नीचे दिए गए लिंक में समस्या के लिए भी काफी चर्चा है।

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660

मैं जीसीसी के दो विभिन्न संस्करणों के साथ ऊपर अपने कोड की कोशिश की है: 4.1.2 एक RedHat 5.7 बॉक्स के, और यह कोई तरीका नहीं है 0x1000 पर गठबंधन में wre स्थानीय सरणियों आपकी समस्या का (इसी तरह विफल रहा है बाइट बाध्यता)। मैंने फिर रेडहाट 6.3 पर जीसीसी 4.4.6 के साथ अपना कोड आजमाया, और यह बेकार ढंग से काम करता था (स्थानीय सरणी गठबंधन की गई थीं)।

http://code.mythtv.org/trac/ticket/6535

वैसे भी, जैसे आप जीसीसी में एक बग, बाद के संस्करणों में तय किया प्रतीत होता है यह लग रहा है: मिथक टीवी लोगों के लिए एक समान समस्या (है कि जीसीसी पैच ऊपर ठीक करने के लिए लग रहा था) था।

+3

लिंक किए गए बग जीसीसी 4.6 के अनुसार इस समस्या के साथ पहली रिलीज सभी आर्किटेक्चर के लिए पूरी तरह से तय की गई थी। – textshell

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