61
задан 9 May 2019 в 17:34

2 ответа

Локальная переменная, объявленная как static, имеет время жизни всей под управлением программы и обычно хранится в сегменте данных. Компиляторы реализуют это при наличии раздела, который имеет значения в них.

Локальные переменные, не объявленные как статичные обычно живой на стеке и, должны быть инициализированы каждый раз, когда объем переменной вводится.

Рассмотрение блока для static случай, MSVC 2 015 выводов следующее:

; 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
?Arr@?1??tfuuuuuuu@@9@9 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 [110]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 ?Arr@?1??tfuuuuuuu@@9@9[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  __real@3e45798ee2308c3a
PUBLIC  __real@3f40e1cf9350aa3c
PUBLIC  __real@3f43b1f90beff84b
PUBLIC  __real@3f4c6220dc6e8066
PUBLIC  __real@3f4ea4c648794089
PUBLIC  __real@3f50023666188dc0
PUBLIC  __real@3f53957e56f300e9
PUBLIC  __real@3f55235d7d33b25f
PUBLIC  __real@3f5828f66e5bd33a
PUBLIC  __real@3f5c044284dfce31
PUBLIC  __real@3f5c87c05341c674
...
EXTRN   @__security_check_cookie@4:PROC
EXTRN   __chkstk:PROC
EXTRN   _memset:PROC
EXTRN   ___security_cookie:DWORD
EXTRN   __fltused:DWORD
;   COMDAT __real@bff0000000000000
CONST   SEGMENT
__real@bff0000000000000 DQ 0bff0000000000000r   ; -1
CONST   ENDS
;   COMDAT __real@bfefffffdfc9a9ad
CONST   SEGMENT
__real@bfefffffdfc9a9ad DQ 0bfefffffdfc9a9adr   ; -1
CONST   ENDS
;   COMDAT __real@bfefffffbf935359
CONST   SEGMENT
__real@bfefffffbf935359 DQ 0bfefffffbf935359r   ; -1
CONST   ENDS
;   COMDAT __real@bfefffff9f5cfd06
CONST   SEGMENT
__real@bfefffff9f5cfd06 DQ 0bfefffff9f5cfd06r   ; -1
CONST   ENDS
;   COMDAT __real@bfefffff7f26a6b3
CONST   SEGMENT
__real@bfefffff7f26a6b3 DQ 0bfefffff7f26a6b3r   ; -1
CONST   ENDS
;   COMDAT __real@bfefffff5ef05060
CONST   SEGMENT
__real@bfefffff5ef05060 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 __real@4060c00000000000
    movsd   QWORD PTR _Arr$[ebp], xmm0
    movsd   xmm0, QWORD PTR __real@3fe15efd20a7955b
    movsd   QWORD PTR _Arr$[ebp+8], xmm0
    movsd   xmm0, QWORD PTR __real@3fdf59701e4b19af
    movsd   QWORD PTR _Arr$[ebp+16], xmm0
    movsd   xmm0, QWORD PTR __real@bfd8e38e9ab7fcb1
    movsd   QWORD PTR _Arr$[ebp+24], xmm0
    movsd   xmm0, QWORD PTR __real@bfe59f22c01e68a1
    movsd   QWORD PTR _Arr$[ebp+32], xmm0
    movsd   xmm0, QWORD PTR __real@bfeb13b15d5aa410
    movsd   QWORD PTR _Arr$[ebp+40], xmm0
    movsd   xmm0, QWORD PTR __real@bfe2c2355f07776e
    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    @__security_check_cookie@4
    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

Вместо того, чтобы генерировать явные инструкции скопировать каждое значение, gcc просто звонит memcpy для копирования значений с глобальных данных в локальный массив, так генерирование кода инициализации намного быстрее.

, Таким образом, мораль истории - то, что MSVC очень неэффективен в том, как это инициализирует локальные переменные.

кроме того, как отмечено в комментариях, это подтвержденная ошибка , который должен быть зафиксированным в VS 2019.

45
ответ дан 31 October 2019 в 16:21

const или нет, не - static функционируют локальные, должен быть создан каждый раз, когда функция вводится, и объявление достигнуто. Ваш компилятор проводит время, генерируя код для выполнения того действия во времени выполнения, которое может быть трудным, когда инициализатор супер длинен.

constrast, static из этой формы могли просто уронить ее начальное значение в исполняемый файл где-нибудь, без необходимого вращения во время выполнения.

Это действительно походит на что-то вроде проблемы QoI с Вашим компилятором, если Вы действительно видите большую разницу во время изготовления (особенно, поскольку 1.2 МБ не , что много данных), но две части кода являются существенно различными и огромными инициализаторами для вещей, предназначенных для проживания "на стеке", обычно что-то для предотвращения.

28
ответ дан 31 October 2019 в 16:21

Другие вопросы по тегам:

Похожие вопросы: