我将一些C99代码移植到C ++中,这些代码大量使用可变长度数组(VLA)。 我用一个在堆上分配内存的数组类来replaceVLA(堆栈分配)。 性能下降幅度很大,下降了3.2倍(见下面的基准)。 我可以在C ++中使用什么样的VLA快速replace? 我的目标是在重写C ++代码时将性能降到最低。 我build议的一个想法是编写一个在类中包含一个固定大小的存储(即可以堆栈分配)的数组类,并将其用于小型数组,并自动切换到大型数组的堆分配。 我的这个实现是在post的最后。 它工作得很好,但我仍然无法达到原始C99代码的性能。 要接近它,我必须增加这个固定大小的存储( MSL以下)到我不舒服的大小。 我不想在堆栈上分配太大的数组, 即使是那些不需要它的小数组,因为我担心它会触发堆栈溢出。 C99 VLA实际上不太容易这样做,因为它永远不会使用比需要更多的存储空间。 我来到std::dynarray ,但我的理解是,它没有被接受到标准(还?)。 我知道clang和gcc支持C ++中的VLA,但我也需要它与MSVC一起工作。 实际上,更好的可移植性是C ++重写的主要目标之一(另一个目标是将程序本来就是一个命令行工具)编译成可重用的库。 基准 MSL是MSL组大小,高于此大小我切换到堆分配。 一维和二维数组使用不同的值。 原始C99代码:115秒。 MSL = 0(即堆分配):367秒(3.2x)。 1D-MSL = 50,2D-MSL = 1000:187秒(1.63x)。 1D-MSL = 200,2D-MSL = 4000:143秒(1.24x)。 1D-MSL = 1000,2D-MSL = 20000:131(1.14x)。 增加MSL进一步提高了性能,但最终程序将开始返回错误的结果(我认为是由于堆栈溢出)。 这些基准与OS X上的clang 3.7一样,但是gcc 5显示了非常相似的结果。 码 这是我现在使用的“smallvector”实现。 我需要一维和二维vector。 我切换到大小MSL以上的堆分配。 template<typename […]
有使用变长数组的开销吗? 数组的大小可以在运行时通过命令行parameter passing吗? 为什么它被引入,相比自动和dynamic分配一个数组?
我写了一个C程序,它接受来自用户的整数input,用作整型数组的大小,并使用该值声明给定大小的数组,并通过检查数组大小来确认它。 码: #include <stdio.h> int main(int argc, char const *argv[]) { int n; scanf("%d",&n); int k[n]; printf("%ld",sizeof(k)); return 0; } 令人惊讶的是这是正确的! 该程序能够创build所需大小的数组。 但是所有的静态内存分配都是在编译时完成的,在编译期间n的值是未知的,那么编译器如何才能分配所需大小的内存呢? 如果我们可以像这样分配所需的内存,那么使用malloc()和calloc()进行dynamic分配有什么用处呢?
我find了一个函数来计算一个数字的平方: int p(int n) { int a[n]; //works on C99 and above return (&a)[n] – a; } 它返回n 2的值。 问题是,它是如何做到的? 经过一些testing,我发现(&a)[k]和(&a)[k+1]是sizeof(a) / sizeof(int) 。 这是为什么?
我怎样才能使用在Visual C ++中定义的VLA,可变长度的数组,如C99,或者根本不可能? 是的,我知道C ++标准是基于C89的,并且在C89标准中没有可用的VLA,因此在C ++中是不可用的,但MSVC ++也应该是C编译器,也可以使用/ TC编译参数( Compile as C Code (/TC) )。 但是这样做似乎并没有启用VLA,编译过程在编译为C ++( Compile as C++ Code (/TP) )时也会出现相同的错误。 也许MSVC ++ C编译器只是C89兼容或我缺less的东西(一些特殊的结构或编译/定义)? 代码示例: #include <stdlib.h> int main(int argc, char **argv) { char pc[argc+5]; /* do something useful with pc */ return EXIT_SUCCESS; } 编译错误: 错误C2057:预期的常量expression式 错误C2466:不能分配一个常量大小为0的数组 错误C2133:'pc':未知的大小
今天我用一些C代码帮助我的一个朋友,我发现了一些奇怪的行为,我无法解释他为什么会这样。 我们有一个整数列表TSV文件,每行一个int。 第一行是列表中的行数。 我们也有一个非常简单的“读取文件”的交stream文件。 第一行读到n,行数,然后有一个初始化: int list[n] 最后是一个fscanf的for循环。 对于小n(直到100.000),一切都很好。 然而,我们发现当n很大时(10 ^ 6),会发生段错误。 最后,我们将列表初始化更改为 int *list = malloc(n*sizeof(int)) 一切都好,即使是非常大的n。 有人可以解释为什么会发生? 是什么导致segfault与int list [n],当我们开始使用list = malloc(n * sizeof(int))时停止?
不,等等,跟我一起… VLA总是一个GCC扩展,但是它们被C99采用: [C99: 6.7.5.2/4]:如果大小不存在,则数组types是不完整的types。 如果size的大小是*,而不是一个expression式,则数组types是一个非指定大小的可变长度的数组types,它只能在具有函数原型作用域的声明中使用; 这样的数组仍然是完整的types。 如果大小是一个整数常量expression式,并且元素types具有已知的常量大小,则数组types不是可变长度数组types; 否则,数组types是一个可变长度的数组types。 C99也被称为ISO/IEC 9899:1999 。 现在: [C++11: 1.1/2]: C ++是一种基于ISO / IEC 9899:1999(以下简称C标准)规定的C编程语言的通用编程语言。 除了C提供的function之外,C ++还提供额外的数据types,类,模板,exception,命名空间,运算符重载,函数名称重载,引用,免费商店pipe理操作员以及其他库设施。 那么C ++ 11也不应该有VLA吗?
在过去的几年中,我并没有使用C语言。 当我今天看到这个问题时 ,我碰到了一些我不熟悉的C语法。 显然在C99中 ,以下语法是有效的: void foo(int n) { int values[n]; //Declare a variable length array } 这似乎是一个非常有用的function。 有没有关于将其添加到C ++标准的讨论,如果是的话,为什么它被省略? 一些潜在的原因: 供编译器厂商使用 与标准的其他部分不兼容 function可以与其他C ++结构模拟 C ++标准规定数组大小必须是一个常量expression式(8.3.4.1)。 是的,我当然知道,在玩具的例子中,可以使用std::vector<int> values(m); ,但是这从堆中分配内存而不是堆栈。 如果我想要一个multidimensional array,如: void foo(int x, int y, int z) { int values[x][y][z]; // Declare a variable length array } vector版本变得非常笨拙: void foo(int x, int y, […]