c किस प्रकार का सी 11 डेटा प्रकार AMD64 ABI के अनुसार एक सरणी है



assembly types (1)

बियर एरेज़ के रूप में सी और सी ++ फ़ंक्शन एआरजी पॉइंटर्स को सिकुड़ते हैं, जैसे कई अन्य संदर्भों में।

स्ट्रेट्स या union अंदर के struct नहीं होते, और वे मूल्य से पारित होते हैं। यही कारण है कि एबीआई को यह ध्यान देने की जरूरत है कि वे कैसे पारित हो गए हैं, भले ही सी में नंगे एरे के लिए ऐसा नहीं हो।

जैसा कीथ थॉमसन बताते हैं , सी मानक का प्रासंगिक भाग N1570 अनुभाग 6.7.6.3 पैरा 7 है

"प्रकार की सरणी" के रूप में एक पैरामीटर की घोषणा को "योग्य सूचक को टाइप करने के लिए" समायोजित किया जाएगा, जहां प्रकार के क्वालिफायर (यदि कोई हैं) वे हैं जो [और] सरणी प्रकार व्युत्पत्ति के भीतर निर्दिष्ट हैं ... ( foo[static 10] बारे में सामग्री foo[static 10] , नीचे देखें)

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

शब्दावली: x86-64 एबीआई डॉक्टर एक ही शब्दावली का उपयोग एआरएम के रूप में करता है, जहां struct और एरेज़ "समुच्चय" होते हैं (अनुक्रमिक पते पर कई तत्व)। इसलिए वाक्यांश "समुच्चय और यूनियनों" बहुत ऊपर आता है, क्योंकि union को भाषा और एबीआई द्वारा इसी प्रकार से संभाला जाता है।

यह संमिश्र प्रकार (स्ट्रेट / यूनियन / क्लास) को संभालने के लिए पुनरावर्ती नियम है जो एबीआई में खेलने के लिए एआरआई-पासिंग नियम लाता है। यह एकमात्र तरीका है जिसे आप एएसएम देखेंगे जो स्टैक्स में सरणी को फ़ंक्शन एआरजी के भाग के रूप में प्रतिलिपि बनाता है, सी या सी ++ के लिए

struct s { int a[8]; };
void ext(struct s byval);

void foo() { struct s tmp = {{0}}; ext(tmp); }

gcc6.1 इसे निम्न के लिए (AMD64 SysV ABI के साथ, -O3 के साथ) संकलित करता है :

    sub     rsp, 40    # align the stack and leave room for `tmp` even though it's never stored?
    push    0
    push    0
    push    0
    push    0
    call    ext
    add     rsp, 72
    ret

X86-64 एबीआई में, पास-बाय-वैल्यू वास्तविक प्रतिलिपि (रजिस्टरों या स्टैक में) के द्वारा होता है, छिपा हुआ संकेतक द्वारा नहीं

नोट करें कि रिटर्न-बाय- rdi एक पॉइंटर को "छुपी" पहले आरजी ( rdi ) के रूप में पारित करता है, जब रिटर्न का मान rdx:rax के 128 बिट संयोजन में फिट होने के लिए बहुत बड़ा होता है rdx:rax (और वेक्टर को वापस नहीं लौटाया जाता है वेक्टर रेज़, इत्यादि आदि)

एबीआई के लिए निश्चित आकार के ऑब्जेक्ट्स से छिपी संकेतक का उपयोग करना संभव होगा, और कहा जाता है कि फ़ंक्शन को मूल को संशोधित न करने के लिए, परन्तु ऐसा नहीं है जो x86-64 ABI को चुनता है। यह कुछ मामलों में बेहतर होगा (विशेषकर अकुशल सी ++ के लिए बिना किसी संशोधन के (उदा। व्यर्थ)) नकल की, लेकिन अन्य मामलों में खराब है।

SysV ABI बोनस रीडिंग : जैसा कि x 86 टैग विकी बताता है, एबीआई मानक का वर्तमान संस्करण पूरी तरह से उस व्यवहार को पूरी तरह से दस्तावेज नहीं करता है, जो कंपाइलर्स इस पर भरोसा करते हैं: क्लैंक / जीसीसी साइन / शून्य 32 बिट के लिए संकीर्ण एग्रेड्स का विस्तार करते हैं

नोट करें कि वाकई गारंटी देता है कि फंक्शन आरजी एक निश्चित-आकार की सरणी है, C99 और बाद में आपको static खोजशब्द को एक नए तरीके से उपयोग करने देता है : सरणी आकार पर। (यह अभी भी एक संकेतक के रूप में पारित हुआ है, निश्चित रूप से। यह एबीआई बदलता नहीं है)।

void bar(int arr[static 10]);

यह sizeof(arr) काम देता है जैसा कि आप फ़ंक्शन के अंदर अपेक्षा कर सकते हैं, और कंबाइलर चेतावनियों को सीमा से बाहर जाने के बारे में अनुमति देता है यह भी संभवतः बेहतर अनुकूलन सक्षम बनाता है यदि कंपाइलर जानता है कि उसे सी स्रोत नहीं होने वाले तत्वों तक पहुंचने की अनुमति है। ( इस ब्लॉग पोस्ट को देखें)।

सी ++ के लिए एक ही खोजशब्द पृष्ठ इंगित करता है कि आईएसओ सी ++ static इस प्रयोग का समर्थन नहीं करता है; यह सी -9 9 चर-लंबाई-सरणियों और कुछ अन्य उपहारों के साथ, जो सी ++ के पास नहीं है, उन सी-फ़िल विशेषताओं में से एक और है।

C ++ में, आप कॉल करने वाले को संकलित-समय के आकार की जानकारी प्राप्त करने के लिए std::array<int,10> का उपयोग कर सकते हैं। हालांकि, आपको इसे मैन्युअल रूप से संदर्भ से पास करना होगा यदि आप चाहते हैं कि यह वही है, क्योंकि यह निश्चित रूप से सिर्फ एक वर्ग है जिसमें int arr[10] शामिल है सी-स्टाइल सरणी के विपरीत, यह स्वचालित रूप से T* को क्षय नहीं करता है

एआरएम डॉक्टर जो आपने लिंक किया है, वास्तव में एरे को एक समग्र प्रकार कहते हैं: धारा 4.3 संमिश्र प्रकार (जो संरेखण की चर्चा करता है) समतुल्य प्रकार से सरणियों को अलग करता है, भले ही वे समुच्चय के लिए इसकी परिभाषा का एक विशेष मामला दिखाई देते हैं।

एक संमिश्र प्रकार एक या अधिक मौलिक डेटा प्रकार का एक संग्रह है जो कि प्रक्रिया कॉल स्तर पर एक इकाई के रूप में नियंत्रित किया जाता है। एक संमिश्र प्रकार इनमें से कोई भी हो सकता है:

  • कुल मिलाकर, जहां सदस्यों को क्रमशः मेमोरी में रखा जाता है
  • एक संघ, जहां प्रत्येक सदस्य का एक ही पता होता है
  • एक सरणी, जो कि किसी अन्य प्रकार का दोहराया क्रम है (इसका आधार प्रकार)।

परिभाषाएं पुनरावर्ती हैं; अर्थात, प्रत्येक प्रकार में एक सदस्य के रूप में एक समग्र प्रकार हो सकता है

"समग्र" एक छत्र शब्द है जिसमें सरणियों, स्ट्रेंक्ट्स और यूनियन शामिल हैं।

मैं OSX पर इस्तेमाल किया गया x86_64 के कॉलिंग सम्मेलन की खोज कर रहा था और सिस्टम वी x86-64 एबीआई मानक में "समुच्चय और यूनियन" नामक अनुभाग को पढ़ रहा था)। यह सरणियों का उल्लेख करता है और मैंने सोचा था कि एक निश्चित लंबाई सी सरणी की तरह था, जैसे int[5]

मैं "3.2.3 पैरामीटर पासिंग" के बारे में पढ़ने के लिए नीचे चला गया कि कैसे सरणियों को पारित किया गया और अगर मैं सही ढंग से समझ रहा हूं तो यूआईटी 8_टी uint8_t[3] जैसा कुछ रजिस्टरों में पारित किया जाना चाहिए क्योंकि यह 1 के नियम 1 के द्वारा लगाए गए चार आठबीट सीमा से छोटा है कुल प्रकार का वर्गीकरण (नीचे पृष्ठ 18)

संकलन के बाद मैं देखता हूं कि इसके बजाय इसे एक सूचक के रूप में पारित किया जा रहा है (मैं XX 7.3.1 से OSX 10.11.6 पर क्लैंग -703.0.31 के साथ संकलित कर रहा हूं)।

मैं संकलन करने के लिए उपयोग कर रहा था उदाहरण स्रोत इस प्रकार है:

#include <stdio.h>

#define type char

extern void doit(const type[3]);
extern void doitt(const type[5]);
extern void doittt(const type[16]);
extern void doitttt(const type[32]);
extern void doittttt(const type[40]);

int main(int argc, const char *argv[]) {
  const char a[3] = { 1, 2, 3 };
  const char b[5] = { 1, 2, 3, 4, 5 };
  const char c[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
  const char d[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
  const char e[40] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };

  doit(a);
  doitt(b);
  doittt(c);
  doitttt(d);
  doittttt(e);
}

मैं ac नाम पर फ़ाइल को डंप करता हूं और संकलित करने के लिए निम्न आदेश का उपयोग करता हूं: clang -c ac -o ao मैं ओबोल का निर्माण करने के लिए असेंबली का विश्लेषण करने के लिए उपयोग करता हूं ( otool -tV ao चलाकर) और निम्नलिखित आउटपुट प्राप्त करें:

a.o:
(__TEXT,__text) section
_main:
0000000000000000    pushq   %rbp
0000000000000001    movq    %rsp, %rbp
0000000000000004    subq    $0x10, %rsp
0000000000000008    leaq    _main.a(%rip), %rax
000000000000000f    movl    %edi, -0x4(%rbp)
0000000000000012    movq    %rsi, -0x10(%rbp)
0000000000000016    movq    %rax, %rdi
0000000000000019    callq   _doit
000000000000001e    leaq    _main.b(%rip), %rdi
0000000000000025    callq   _doitt
000000000000002a    leaq    _main.c(%rip), %rdi
0000000000000031    callq   _doittt
0000000000000036    leaq    _main.d(%rip), %rdi
000000000000003d    callq   _doitttt
0000000000000042    leaq    _main.e(%rip), %rdi
0000000000000049    callq   _doittttt
000000000000004e    xorl    %eax, %eax
0000000000000050    addq    $0x10, %rsp
0000000000000054    popq    %rbp
0000000000000055    retq

या समतुल्य रूप से, यह ग्लेब्ल्ट संकलक एक्सप्लोरर पर है जो क्लैंग 3.7 है , जो कि लिनक्स को लक्षित करता है जो उसी एबीआई का उपयोग करता है।

इसलिए, मैं सोच रहा था कि कोई मुझे सीए 11 में कौन से डेटा प्रकारों को एरेज़ पर लागू कर सकता है। (यह C11 का उपयोग करने के लिए झुकाव चूक की तरह लग रहा है - यहां C99 इनलाइन फ़ंक्शन के तहत यहां पर दिखाई देता है)।

मैंने एआरएम के साथ भी इसी तरह की जांच की और इसी तरह के परिणाम पाया, भले ही एआरएम मानक भी निर्दिष्ट करता है कि एक सरणी समग्र प्रकार मौजूद है

इसके अलावा, क्या कुछ मानक में कहीं यह निर्दिष्ट किया गया है कि एक निश्चित लंबाई सरणी को एक सूचक के रूप में माना जाना चाहिए?





calling-convention