C++;C型数组的等价性 我听到很多人说C++在所有方面都比C快,但是更干净,更漂亮。p> 虽然我不反对C++非常优雅,而且速度很快的事实,但我没有找到任何关键内存访问或处理器绑定应用程序的替代。p> 问题< /强>:C型数组在性能方面是否存在等价于C++?< /P>
下面的例子是人为设计的,但我对解决现实问题感兴趣:我开发了图像处理应用程序,那里的像素处理量很大C++;C型数组的等价性 我听到很多人说C++在所有方面都比C快,但是更干净,更漂亮。p> 虽然我不反对C++非常优雅,而且速度很快的事实,但我没有找到任何关键内存访问或处理器绑定应用程序的替代。p> 问题< /强>:C型数组在性能方面是否存在等价于C++?< /P>,c++,c,performance,optimization,C++,C,Performance,Optimization,下面的例子是人为设计的,但我对解决现实问题感兴趣:我开发了图像处理应用程序,那里的像素处理量很大 double t; // C++ std::vector<int> v; v.resize(1000000,1); int i, j, count = 0, size = v.size(); t = (double)getTickCount(); for(j=0;j<1000;j++) { count = 0; for(i=0;i<size;i++)
double t;
// C++
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();
t = (double)getTickCount();
for(j=0;j<1000;j++)
{
count = 0;
for(i=0;i<size;i++)
count += v[i];
}
t = ((double)getTickCount() - t)/getTickFrequency();
std::cout << "(C++) For loop time [s]: " << t/1.0 << std::endl;
std::cout << count << std::endl;
// C-style
#define ARR_SIZE 1000000
int* arr = (int*)malloc( ARR_SIZE * sizeof(int) );
int ci, cj, ccount = 0, csize = ARR_SIZE;
for(ci=0;ci<csize;ci++)
arr[ci] = 1;
t = (double)getTickCount();
for(cj=0;cj<1000;cj++)
{
ccount = 0;
for(ci=0;ci<csize;ci++)
ccount += arr[ci];
}
free(arr);
t = ((double)getTickCount() - t)/getTickFrequency();
std::cout << "(C) For loop time [s]: " << t/1.0 << std::endl;
std::cout << ccount << std::endl;
注意:getTickCount()
来自第三方库。如果您想测试,只需替换为您最喜欢的时钟测量值
更新:
我使用VS 2010,发布模式,其他默认的
< P>动态大小数组的C++等价物是<代码> STD::向量< /代码>。一个固定大小的数组的C++等价物将是“代码> STD::数组< /COD>或<代码> STD:::Tr1::数组< /COD>前C ++ 11。 如果向量代码没有重新调整大小,很难看出它比使用动态分配的C数组慢多少,前提是编译时启用了一些优化 注意:按照发布的方式运行代码,在x86上的GCC4.4.3上编译,编译器选项 g++-Wall-Wextra-pedanticerrors-O2-std=c++0x 结果重复地接近 (C++)循环时间[us]:507888 一百万 (C) 循环时间[美国]:496659 一百万因此,在少量试验后,
std::vector
变体似乎慢了约2%。我会考虑这个兼容的性能。 你指出的是,访问对象总是会有一点开销,所以访问<代码>向量>不会比访问一个好的旧数组快。
但是即使使用数组是“C时尚”,它仍然是C++,所以不会是问题。
然后,正如@juanchopanza所说,在C++11中有
std::array
,它可能比std::vector
更有效,但专门用于固定大小的数组。简单回答:您的基准测试有缺陷
较长的答案:你需要打开全优化以获得C++的性能优势。然而,你的基准仍然有缺陷
一些意见:std::vector
有动态重新分配的开销,请尝试std::array
。
具体来说,默认情况下,microsoft的stl具有
cout通常编译器会做所有的优化。。。你只需要选择一个好的编译器,这似乎是一个编译器的问题。对于C数组,编译器检测模式,使用自动矢量化并发出SSE指令。对于vector来说,它似乎缺乏必要的智能
如果我强制编译器不使用SSE,结果非常相似(使用g++-mno mmx-mno SSE-msoft float-O3测试):
下面是生成此输出的代码。它基本上是您问题中的代码,但没有任何浮点
#include <iostream>
#include <vector>
#include <sys/time.h>
using namespace std;
long getTickCount()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
int main() {
long t;
// C++
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();
t = getTickCount();
for(j=0;j<1000;j++)
{
count = 0;
for(i=0;i<size;i++)
count += v[i];
}
t = getTickCount() - t;
std::cout << "(C++) For loop time [us]: " << t << std::endl;
std::cout << count << std::endl;
// C-style
#define ARR_SIZE 1000000
int* arr = new int[ARR_SIZE];
int ci, cj, ccount = 0, csize = ARR_SIZE;
for(ci=0;ci<csize;ci++)
arr[ci] = 1;
t = getTickCount();
for(cj=0;cj<1000;cj++)
{
ccount = 0;
for(ci=0;ci<csize;ci++)
ccount += arr[ci];
}
delete arr;
t = getTickCount() - t;
std::cout << "(C) For loop time [us]: " << t << std::endl;
std::cout << ccount << std::endl;
}
#包括
#包括
#包括
使用名称空间std;
long getTickCount()
{
结构时间值电视;
gettimeofday(&tv,NULL);
返回tv.tv_sec*1000000+tv.tv_usec;
}
int main(){
长t;
//C++
std::向量v;
v、 调整大小(1000000,1);
int i,j,count=0,size=v.size();
t=getTickCount();
对于(j=0;j
问题:C++中的C样式数组在性能方面是否有等价关系?
< >回答:编写C++代码!了解你的语言,了解你的标准库并使用它。标准算法是正确的、可读的和快速的(他们知道如何在当前编译器上实现它是最好的)。
在Ubuntu上使用g++-O3-std=c++0x
4.6.3版编译
<>你的代码我的输出和你的相似。U.S.P.22136给出了一个很好的答案。……<…>我怀疑你做了一个完全优化C++ C++的构建。这个代码中没有指针数组…我只是测试了这个(用一个计算机,用一个特定的编译器稍微修改了代码)。没有优化,“C++风格”。一个比C风格慢三分之一,优化后,“C++风格”一个总是比C样式快一点(而且都比没有优化快)。我在机器上的C++和C++版本都得到了215秒。(GCC和G+在X8664机器上)。(.534/.605)使用g++-O3编译时,两个版本的运行时相同。向量初始化后,分析就会开始,所以这不会是问题…从零开始调整大小可能与分配没有什么不同。@DavidSchwartz可能,但它似乎不必要,并且是对std::vector不太了解的一个标志…但是它比较慢,那么现在呢我需要一些测试,以证明它实际上是比较慢的。运行我自己的版本,用GCC 4.6和4.8编译的代码,我得到了C和C++版本的相同性能。“有STD::在C++ 11中的数组,它比STD::vector更有效。”你能备份这个吗?如果你对一个向量执行改变其大小的操作,比如循环推回而不调整大小,数组可能更有效,例如,因为向量涉及额外的间接级别(它包含一个指向数据的指针,而array
包含数据)。是的,编译器会将该数据指针的读取提升到循环之外,但这样做需要一个寄存器(将其存储在内存中),而对std::array
的访问可以直接基于堆栈指针。使用一个寄存器是一个次要的性能
######### jump to the loop end
jg .LBB0_11
.LBB0_3: # %..split_crit_edge
.Ltmp2:
# print the benchmark result
movl $0, 12(%esp)
movl $25, 8(%esp)
movl $.L.str, 4(%esp)
movl std::cout, (%esp)
calll std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
.Ltmp3:
# BB#4: # %_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.exit
.Ltmp4:
movl std::cout, (%esp)
calll std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
.Ltmp5:
# BB#5: # %_ZNSolsEd.exit
movl %eax, %ecx
movl %ecx, 28(%esp) # 4-byte Spill
movl (%ecx), %eax
movl -24(%eax), %eax
movl 240(%eax,%ecx), %ebp
testl %ebp, %ebp
jne .LBB0_7
# BB#6:
.Ltmp52:
calll std::__throw_bad_cast()
.Ltmp53:
.LBB0_7: # %.noexc41
cmpb $0, 28(%ebp)
je .LBB0_15
# BB#8:
movb 39(%ebp), %al
jmp .LBB0_21
.align 16, 0x90
.LBB0_9: # Parent Loop BB0_11 Depth=1
# => This Inner Loop Header: Depth=2
addl (%edi,%edx,4), %ebx
addl $1, %edx
adcl $0, %esi
cmpl %ecx, %edx
jne .LBB0_9
# BB#10: # in Loop: Header=BB0_11 Depth=1
incl %eax
cmpl $1000, %eax # imm = 0x3E8
######### jump back to the print benchmark code
je .LBB0_3
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();
for(j=0;j<1000;j++)
{
count = 0;
for(i=0;i<size;i++)
count += v[i];
}
std::cout << "(C++) For loop time [s]: " << t/1.0 << std::endl;
std::cout << count << std::endl;
(C++) For loop time [us]: 604610
1000000
(C) For loop time [us]: 601493
1000000
#include <iostream>
#include <vector>
#include <sys/time.h>
using namespace std;
long getTickCount()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
int main() {
long t;
// C++
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();
t = getTickCount();
for(j=0;j<1000;j++)
{
count = 0;
for(i=0;i<size;i++)
count += v[i];
}
t = getTickCount() - t;
std::cout << "(C++) For loop time [us]: " << t << std::endl;
std::cout << count << std::endl;
// C-style
#define ARR_SIZE 1000000
int* arr = new int[ARR_SIZE];
int ci, cj, ccount = 0, csize = ARR_SIZE;
for(ci=0;ci<csize;ci++)
arr[ci] = 1;
t = getTickCount();
for(cj=0;cj<1000;cj++)
{
ccount = 0;
for(ci=0;ci<csize;ci++)
ccount += arr[ci];
}
delete arr;
t = getTickCount() - t;
std::cout << "(C) For loop time [us]: " << t << std::endl;
std::cout << ccount << std::endl;
}
void testC()
{
// unchanged
}
void testCpp()
{
// unchanged initialization
for(j=0;j<1000;j++)
{
// how a C++ programmer accumulates:
count = std::accumulate(begin(v), end(v), 0);
}
// unchanged output
}
int main()
{
testC();
testCpp();
}
(C) For loop time [ms]: 434.373
1000000
(C++) For loop time [ms]: 419.79
1000000