我很清楚,可能不会有"c ++中最难找到的错误",但我仍然对其他人可能已经/可能已经遇到的内容感兴趣.
这个问题的想法是在与朋友讨论时产生的.我们同意,通过在您提交的源代码中包含错误来破坏cpp项目必须相当简单......但我们能想到的最好的事情是使用未初始化的变量(在运行时导致随机分段错误) .我相信有更好的方法......?!
想要错误代码的特征:
尽管如此,虽然它必须引人注目,但在代码提交后不应该显而易见......好吧,你明白了.
别担心,我们的考虑纯粹是理论上的(我们不打算破坏任何项目).我们只是认为这是一个很好的思想实验与他人分享:-)
简而言之:
什么是破坏源代码的最微妙的方法,可能会在差异提交(如git)中被忽视,但最终会阻止软件的发布?
(出于测试目的)我编写了一个简单的方法来计算nxn矩阵的转置
void transpose(const size_t _n, double* _A) {
for(uint i=0; i < _n; ++i) {
for(uint j=i+1; j < _n; ++j) {
double tmp = _A[i*_n+j];
_A[i*_n+j] = _A[j*_n+i];
_A[j*_n+i] = tmp;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当使用优化级别O3或Ofast时,我期望编译器展开一些循环,这将导致更高的性能,尤其是当矩阵大小是2的倍数(即,每次迭代可以执行双循环体)或类似时.相反,我测量的恰恰相反.2的权力实际上表明执行时间显着增加.
这些尖峰也是64的固定间隔,间隔128更明显,依此类推.每个尖峰延伸到相邻的矩阵大小,如下表所示
size n time(us)
1020 2649
1021 2815
1022 3100
1023 5428
1024 15791
1025 6778
1026 3106
1027 2847
1028 2660
1029 3038
1030 2613
Run Code Online (Sandbox Code Playgroud)
我使用gcc版本4.8.2编译但是同样的事情发生在clang 3.5上,所以这可能是一些通用的东西?
所以我的问题基本上是:为什么执行时间周期性增加?是否有一些通用的东西与任何优化选项一起出现(就像clang和gcc一样)?如果是这样的优化选项导致了这个?
这怎么可能如此重要,即使O0版本的程序在512的倍数时优于03版本?

编辑:注意此(对数)图中峰值的大小.转换具有优化的1024x1024矩阵实际上花费的时间与在没有优化的情况下转置1300x1300矩阵一样多.如果这是一个缓存故障/页面错误问题,那么有人需要向我解释为什么内存布局对于程序的优化版本是如此显着不同,它失败的功能为2,只是为了恢复高性能稍大的矩阵.缓存故障是否应该创建更多类似步骤的模式?为什么执行时间会再次下降?(为什么优化会创建以前不存在的缓存错误?)
编辑:以下应该是gcc生成的汇编代码
没有优化(O0):
_Z9transposemRPd:
.LFB0:
.cfi_startproc
push rbp …Run Code Online (Sandbox Code Playgroud) 这个问题出现在这个问题的背景下:找到未执行的c ++代码行
在搜索此问题时,大多数人都试图将代码和变量添加到同一部分中 - 但这绝对不是问题所在.这是一个最小的工作示例:
unsigned cover() { return 0; }
#define COV() do { static unsigned cov[2] __attribute__((section("cov"))) = { __LINE__, cover() }; } while(0)
inline void foo() {
COV();
}
int main(int argc, char* argv[])
{
COV();
if (argc > 1)
COV();
if (argc > 2)
foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果与g++ -std=c++11 test.cpp(g ++(GCC)4.9.2 20150212(Red Hat 4.9.2-6))出现以下错误:
test.cpp:6:23: error: cov causes a section type conflict with cov
COV();
^
test.cpp:11:30: note: ‘cov’ was declared here …Run Code Online (Sandbox Code Playgroud) 作为我的单元测试的一部分,我想确保测试的代码覆盖率.目的是REQUIRE_TEST在代码中的某处放置类似宏的东西,并检查是否所有这些都被调用.
void foo(bool b) {
if (b) {
REQUIRE_TEST
...
} else {
REQUIRE_TEST
...
}
}
void main() {
foo(true);
output_all_missed_REQUIRE_macros();
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,输出将包括源文件和宏的行.
我最初的想法是让宏创建静态对象,这些对象会在某个映射中注册自己,然后检查是否所有这些都被调用
#define REQUIRE_TEST \
do { \
static ___RequiredTest requiredTest(__func__, __FILE__, __LINE__);\
(void)requiredTest;\
___RequiredTest::increaseCounter(__func__, __FILE__, __LINE__);\
} while(false)
Run Code Online (Sandbox Code Playgroud)
但静态对象仅在第一次调用代码时创建.因此,映射仅包含在下一行中计算的函数 - 找不到丢失的REQUIRE_TEST宏.在__attribute__((used))这种情况下被忽略.
gcc有一个很好的属性__attribute__((constructor)),但显然选择在放在这里时忽略它(代码而不是静态对象)
struct teststruct { \
__attribute__((constructor)) static void bla() {\
___RequiredTest::register(__func__, __FILE__, __LINE__); \
} \
};\
Run Code Online (Sandbox Code Playgroud)
以及
[]() __attribute__((constructor)) { \
___RequiredTest::register(__func__, __FILE__, __LINE__); \
};\
Run Code Online (Sandbox Code Playgroud)
我现在想到的唯一出路是a)手动(或通过脚本)分析常规编译之外的代码(uargh)或b)使用__COUNTER__ …
我想要有自纪元以来的毫秒数.一个流行的解决方案如下所示(此问题的解决方案之一在此处获取时间,以毫秒为单位,最好使用C++ 11 chrono)
#include <iostream>
#include <chrono>
int main() {
auto millitime = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();
std::cout << millitime << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
通过调用输出中的g++类似g++ -std=c++11 main.cpp -o timetest结果来编译它
1372686001
Run Code Online (Sandbox Code Playgroud)
这等于自纪元以来的秒数!
这是glibc中的一个错误吗?用g ++?我的错?
g++ (Debian 4.7.3-4) 4.7.3
ldd (Debian EGLIBC 2.17-6) 2.17
Run Code Online (Sandbox Code Playgroud)
更新:使用g ++ 4.8时可以使用它.所以这是一个gcc bug?!
g++-4.8 (Debian 4.8.1-2) 4.8.1
Run Code Online (Sandbox Code Playgroud)