C 或 C++ 中的边界检查昂贵吗?

问题描述 投票:0回答:2

绑定检查成本高昂 (> x2 倍运行时开销)

我从我的一位教授那里得到了这一点。我对此很困惑。 据我所知,程序中最耗时的部分是IO(来自网络和来自硬盘)。

但是 C 或 C++ 中的边界检查并不总是与这两个输入源相关。 例如,我使用

memcpy(dest, src, length(src))
将一个 buff 的内容复制到 C 中的另一个。在此之前,我检查
src
的大小以防止堆溢出。我能想象的过程是:获取
src
的起始地址和
\x00
中的
src
字节(从汇编语言的角度来看,我将
src
的内容一一复制,看看该字节是否相当于
\x00
)。得到2个地址后,只需将它们相减即可得到
src
的长度。我从记忆中读出了
src
的内容。我们都知道从记忆中读取内容很快。

c++ c
2个回答
12
投票

我刚刚运行了一个程序,并且打开了迭代器边界检查。

运行时间从 789 毫秒变为 2608 毫秒。

所以,是的,这很重要。并非总是如此,但肯定比从未有过。

特别是,边界检查迭代器需要的存储空间至少是简单指针的两倍,而且不容易优化。理论上它们简单高效,但实际上您只是不想做不需要的工作。

哦,我有没有提到编译时间也从 7.72 秒缩短到 13.21 秒?


对于你们当中许多非信徒...
这个微型示例在没有边界检查的情况下需要 130 毫秒,而在使用时则需要 300 毫秒:

#include <stdio.h> #include <stdlib.h> #include <time.h> template<class T> struct Vector { T *b, *e; typedef T &reference; Vector(size_t n) : b(new T[n]), e(b + n) { } template<bool Checked> T &at(size_t i) { if constexpr (Checked) { if (i >= e - b) { abort(); } } return b[i]; } }; template<bool Checked> void test(int N, size_t x, Vector<size_t> &v, bool output) { for (size_t *p = v.b; p != v.e; ++p) { *p = 1; } clock_t begin = clock(); for (int j = 0; j < N; ++j) { for (size_t k = 8, n = v.e - v.b; k < n; ++k) { size_t i = k ^ x; v.at<Checked>(i) += v.at<Checked>(i - 8); v.at<Checked>(i) ^= v.at<Checked>(i - 7); v.at<Checked>(i) -= v.at<Checked>(i - 6); v.at<Checked>(i) ^= v.at<Checked>(i - 5); v.at<Checked>(i) += v.at<Checked>(i - 4); v.at<Checked>(i) ^= v.at<Checked>(i - 3); v.at<Checked>(i) -= v.at<Checked>(i - 2); v.at<Checked>(i) ^= v.at<Checked>(i - 1); } } clock_t end = clock(); if (output) { fprintf( stderr, "%-9s: %u ms\n", Checked ? "Checked" : "Unchecked", static_cast<unsigned int>((clock() - begin) * 1000ULL / CLOCKS_PER_SEC)); } } int main(int argc, char **argv) { size_t x = argc - 1; int N = (1 << 11) + x; Vector<size_t> v((1 << 15) + (x ^ 0x100)); test<true>(N, x, v, false); test<false>(N, x, v, false); // Warm-up round test<true>(N, x, v, true); test<false>(N, x, v, true); test<true>(N, x, v, true); test<false>(N, x, v, true); test<true>(N, x, v, true); test<false>(N, x, v, true); }
    

3
投票
在 20 世纪 80 年代之前,这一直都是事实。

借助现代代码生成和高度流水线化的 CPU 架构,可以在零或很少的额外执行成本下完成边界检查。 这是因为边界检查可以与内存获取并行发生。

© www.soinside.com 2019 - 2024. All rights reserved.