C/C++ में const अरैस्ट और स्टैटिक कॉन्स्ट ऐरे के बीच क्या अंतर है




arrays static (2)

विजुअल स्टूडियो 2015 (Win7, x64, डीबग कॉन्फ़िगरेशन) में निम्न कोड को संकलित करते हुए बहुत, बहुत, बहुत लंबा समय (यानी, 10 मिनट से अधिक) लिया गया

double tfuuuuuuu(int Ind)
{
  const double Arr[600 * 258] = {3.5453, 45.234234234, 234234.234,// extends to 258 values for each line
                                // 599 lines here.....
                                };                     
  return Arr[Ind];
}

लेकिन जब मैंने static कीवर्ड जोड़ा, तो संकलन में आधा सेकंड लग गया

double tfuuuuuuu(int Ind)
{
  static const double Arr[600 * 258] = {3.5453, 45.234234234, 234234.234,// extends to 258 values for each line
                                // 599 lines here.....
                                };                     
  return Arr[Ind];
}

मुझे पता है कि static मतलब है कि परिवर्तनशील के बीच चर अपना मूल्य रखेगा, लेकिन अगर सरणी किसी भी तरह से static तो मुझे static बनाने से क्या फर्क पड़ता है? और संकलन का समय इतना नाटकीय रूप से क्यों बदल गया है?

संपादित करें :

वास्तविक कोड here पाया जा सकता here , (संकलन डिबग मोड में था)

https://code.i-harness.com


जब भी फ़ंक्शन में प्रवेश किया जाता है और घोषणा की जाती है, तब const या नॉन- static फ़ंक्शन लोकल का निर्माण किया जाना चाहिए। आपका कंपाइलर रनटाइम पर उस क्रिया को करने के लिए कोड उत्पन्न करने में समय व्यतीत कर रहा है, जो कि प्रारंभिक सुपर लंबा होने पर कठिन हो सकता है।

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

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


static रूप में घोषित एक स्थानीय चर में पूरे चल रहे कार्यक्रम का जीवनकाल होता है, और इसे आमतौर पर डेटा खंड में संग्रहीत किया जाता है। कंपाइलर इसे एक सेक्शन के द्वारा कार्यान्वित करते हैं, जिसमें उनके मान होते हैं।

स्थानीय चर को स्थिर घोषित नहीं किया जाता है जो आमतौर पर स्टैक पर रहते हैं और हर बार वैरिएबल के दायरे में आने पर इसे आरंभीकृत करना चाहिए।

static मामले के लिए विधानसभा को देखते हुए, MSVC 2015 निम्न आउटपुट देता है:

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24215.1 

    TITLE   MyLBP.c
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

CONST   SEGMENT
?[email protected]?1??[email protected]@[email protected] DQ 04060c00000000000r   ; 134   ; `tfuuuuuuu'::`2'::Arr
    DQ  03fe15efd20a7955br      ; 0.542845
    DQ  03fdf59701e4b19afr      ; 0.489834
    DQ  0bfd8e38e9ab7fcb1r      ; -0.388889
    DQ  0bfe59f22c01e68a1r      ; -0.675676
    DQ  0bfeb13b15d5aa410r      ; -0.846154
    DQ  0bfe2c2355f07776er      ; -0.586207
    DQ  03fefffffbf935359r      ; 1
    ...
    ORG $+1036128
CONST   ENDS
PUBLIC  _tfuuuuuuu
EXTRN   __fltused:DWORD
; Function compile flags: /Odtp
_TEXT   SEGMENT
_Ind$ = 8                       ; size = 4
_tfuuuuuuu PROC
; File c:\users\dennis bush\documents\x2.c
; Line 4
    push    ebp
    mov ebp, esp
; Line 106
    mov eax, DWORD PTR _Ind$[ebp]
    fld QWORD PTR [email protected][email protected]@[email protected][eax*8]
; Line 107
    pop ebp
    ret 0
_tfuuuuuuu ENDP
_TEXT   ENDS
END

जबकि gcc 4.8.5 निम्न आउटपुट देता है:

    .file   "MyLBP.c"
    .text
    .globl  tfuuuuuuu
    .type   tfuuuuuuu, @function
tfuuuuuuu:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    cltq
    movq    Arr.1724(,%rax,8), %rax
    movq    %rax, -16(%rbp)
    movsd   -16(%rbp), %xmm0
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   tfuuuuuuu, .-tfuuuuuuu
    .section    .rodata
    .align 32
    .type   Arr.1724, @object
    .size   Arr.1724, 1238400
Arr.1724:
    .long   0
    .long   1080082432
    .long   547853659
    .long   1071734525
    .long   508238255
    .long   1071602032
    .long   2595749041
    .long   -1076305010
    .long   3223218337
    ...
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)"
    .section    .note.GNU-stack,"",@progbits

तो दोनों विश्व स्तर पर डेटा को परिभाषित करते हैं और उस वैश्विक सरणी को सीधे संदर्भित करते हैं।

अब गैर-स्थैतिक कोड को देखने देता है। VSMC2015 के लिए सबसे पहले:

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24215.1 

    TITLE   MyLBP.c
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _tfuuuuuuu
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
PUBLIC  [email protected]
...
EXTRN   @[email protected]:PROC
EXTRN   __chkstk:PROC
EXTRN   _memset:PROC
EXTRN   ___security_cookie:DWORD
EXTRN   __fltused:DWORD
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bff0000000000000r   ; -1
CONST   ENDS
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bfefffffdfc9a9adr   ; -1
CONST   ENDS
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bfefffffbf935359r   ; -1
CONST   ENDS
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bfefffff9f5cfd06r   ; -1
CONST   ENDS
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bfefffff7f26a6b3r   ; -1
CONST   ENDS
;   COMDAT [email protected]
CONST   SEGMENT
[email protected] DQ 0bfefffff5ef05060r   ; -1
CONST   ENDS
...
; Function compile flags: /Odtp
_TEXT   SEGMENT
_Arr$ = -1238404                    ; size = 1238400
__$ArrayPad$ = -4                   ; size = 4
_Ind$ = 8                       ; size = 4
_tfuuuuuuu PROC
; File c:\users\dennis bush\documents\x2.c
; Line 4
    push    ebp
    mov ebp, esp
    mov eax, 1238404                ; 0012e584H
    call    __chkstk
    mov eax, DWORD PTR ___security_cookie
    xor eax, ebp
    mov DWORD PTR __$ArrayPad$[ebp], eax
; Line 5
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+8], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+16], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+24], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+32], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+40], xmm0
    movsd   xmm0, QWORD PTR [email protected]
    movsd   QWORD PTR _Arr$[ebp+48], xmm0
    ...
    push    1036128                 ; 000fcf60H
    push    0
    lea eax, DWORD PTR _Arr$[ebp+202272]
    push    eax
    call    _memset
    add esp, 12                 ; 0000000cH
; Line 106
    mov ecx, DWORD PTR _Ind$[ebp]
    fld QWORD PTR _Arr$[ebp+ecx*8]
; Line 107
    mov ecx, DWORD PTR __$ArrayPad$[ebp]
    xor ecx, ebp
    call    @[email protected]
    mov esp, ebp
    pop ebp
    ret 0
_tfuuuuuuu ENDP
_TEXT   ENDS
END

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

और अब gcc 4.8.5 संस्करण:

    .file   "MyLBP.c"
    .section    .rodata
    .align 32
.LC0:
    .long   0
    .long   1080082432
    .long   547853659
    .long   1071734525
    .long   508238255
    .long   1071602032
    .long   2595749041
    .long   -1076305010
    .long   3223218337
    .long   -1075470558
    ...
    .text
    .globl  tfuuuuuuu
    .type   tfuuuuuuu, @function
tfuuuuuuu:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $1238416, %rsp
    movl    %edi, -1238404(%rbp)
    leaq    -1238400(%rbp), %rax
    movl    $.LC0, %ecx
    movl    $1238400, %edx
    movq    %rcx, %rsi
    movq    %rax, %rdi
    call    memcpy                       ;   <--------------  call to memcpy
    movl    -1238404(%rbp), %eax
    cltq
    movq    -1238400(%rbp,%rax,8), %rax
    movq    %rax, -1238416(%rbp)
    movsd   -1238416(%rbp), %xmm0
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   tfuuuuuuu, .-tfuuuuuuu
    .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)"
    .section    .note.GNU-stack,"",@progbits

प्रत्येक मान की प्रतिलिपि बनाने के लिए स्पष्ट निर्देश उत्पन्न करने के बजाय, केवल स्थानीय डेटा में वैश्विक डेटा से मूल्यों की प्रतिलिपि बनाने के लिए memcpy कहते हैं, इसलिए आरंभीकरण कोड उत्पन्न करना बहुत तेज है।

तो कहानी का नैतिक यह है कि MSVC बहुत अक्षम है कि यह स्थानीय चर को कैसे आरंभ करता है।

इसके अलावा, जैसा कि टिप्पणियों में कहा गया है, यह एक developercommunity.visualstudio.com/content/problem/407999/… जो वीएस 2019 में तय होने वाला है।





const