在 Visual Studio 2015(Win7、x64、Debug 配置)中编译以下代码需要 非常、非常、非常很长时间(即超过 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 意味着变量将在调用之间保持其值,但是如果数组是 const 无论如何如果我添加 会有什么区别静态?为什么编译时间变化如此之大?
编辑:
实际代码可见here ,(编译处于 Debug模式)
最佳答案
声明为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
?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 $+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 个移动指令。创建这些名称和明确的 Action 是生成代码需要这么长时间的原因。
现在是 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 在初始化局部变量方面效率很低。
此外,正如评论中所述,这是一个 confirmed bug这将在 VS 2019 中修复。
关于c++ - C/C++ 中的 const 数组和静态 const 数组有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56057662/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一