std::ofstrean 不适用于 -O3

std::ofstrean doesn't work with -O3

下面的代码,简单

1) 从命令行参数中获取输入文件名,比如 in.txt

2) 将文件名附加到 "cdf_"

3) 打开一个新名称的文件 cdf_in.txt

4) 简单地读取每一行(每行一个数字)并将其发送到输出文件。

#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

int main(int argc, char* argv[]) 
{
  char *ben = argv[1];    // example: in.txt
  ifstream fin (ben);
  char res[30];

  char *o1 = "cdf_";
  strcat(res, o1);
  strcat(res, ben);
  ofstream fout (res, std::ofstream::out);   // will be cdf_in.txt
  cout << res << endl;

  uint64_t num;  uint64_t sum = 0;
  while (fin >> num) {
    fout << num << endl;
  }
  return 0;
}

通过运行程序没有任何优化,运行正常。但是,通过指定 -O3,它无法创建输出文件。为什么???

$ g++ -o cdf cdf.cpp
cdf.cpp: In function ‘int main(int, char**)’:
cdf.cpp:19: warning: deprecated conversion from string constant to ‘char*’
$ ./cdf in.txt
cdf_in.txt
$ ls cdf*
cdf  cdf.cpp  cdf_in.txt  cdf.py
$ cat cdf_in.txt
10
5
3
2
1

$ rm cdf_in.txt
$ g++ -O3 -o cdf cdf.cpp
cdf.cpp: In function ‘int main(int, char**)’:
cdf.cpp:19: warning: deprecated conversion from string constant to ‘char*’
$ ./cdf in.txt
cdf_in.txt
$ ls cdf*
cdf  cdf.cpp  cdf.py

为什么 fout 不适用于 -O3

您的 strcat(res, o1); 取决于 res[0] == '[=13=]',这可能是正确的,但不能保证(res 是未初始化的本地,因此其内容不是 known/specified).

有可能在您不进行优化时将其初始化为零,但在您进行优化时则不会。

您可以通过初始化 res 或使用 strcpy 而不是 strcat 来修复您要复制到那里的第一个项目(但这仍然会留下可能的缓冲区溢出问题,所以请参阅下文以获得更好的选择)。

或者,当然,您可以编写更像 C++ 而不是 C 的代码,并使用 std::string 而不是 char 数组。

std::string fname("cdf_");
fname += argv[1];

std::ofstream fout(fname.c_str()); // just `fout(fname)` with a C++11 compiler

如果您出于某种原因真的想编写类似 C 的代码,在这种情况下使用 sprintf 可能更容易:

char res[30];

sprintf(res, "cdf_%35s", argv[1]);

std::ofstream fout(res);