c++ - fprintf 在特定字符串上失败,而 shell 函数使用它没有崩溃
问题描述
简短版本:我有一个 C++ 代码,它使用 C 调用fprintf(stdout, some_cpp_str.c_str())
并在此期间崩溃。前 4 次调用很好,只有第 5 次崩溃,我不知道为什么(怀疑字符串中有不可读的字符)。我发布的第一个代码主要是 C,所以我发布了另一个,除了fprintf
(在问题底部添加的代码)之外只有 C++。崩溃(始终)发生在嵌入式设备上。在我自己的 PC 上,代码运行良好
长版:
我有一个从文本中读取行并将它们推入字符串向量的代码。为了检查我的进度,我还在fprintf
填充矢量后将它们显示在屏幕上:
int main(){
char err_msg[256], * line = NULL, *in_file = "...", *keyword = "blah";
size_t len = 0;
ssize_t num_bytes_read;
int i = 1;
std::vector<std::string> lines_vector;
FILE * fp = fopen(in_file, "r");
if (!fp) {
fprintf(stdout,"can't open file %s for reading\n", in_file);
goto EXIT;
}
while ((num_bytes_read = getline(&line, &len, fp)) != -1) {
/* if found keyword inside line */
if (strstr(line, keyword)) {
/* add 3 lines (entry heading, entry body, newline)*/
lines_vector.push_back(std::string(line));
for(int lines_to_copy = 2; lines_to_copy > 0; lines_to_copy--) {
if((num_bytes_read = getline(&line, &len, fp)) == -1) {
fprintf(stdout,"can't read line from %s\n", in_file);
goto EXIT;
}
lines_vector.push_back(std::string(line));
}
}
}
fprintf(stdout,"finished reading from file\n");
EXIT:
fclose(fp);
free(line);
for (std::vector<std::string>::iterator it = lines_vector.begin() ; it != lines_vector.end(); ++it, ++i) {
fprintf(stdout, "%d)", i);
fprintf(stdout, "%s", (*it).c_str());
}
return 0;
}
这在我的虚拟机上运行良好,但我也在嵌入式设备上运行它,它总是在特定行上崩溃。该行是:
certificates local generate name localcert common-name sf country(region) AB auto-regenerate-days 12 auto-regenerate-days-warning 11 e-mail X@Y.com locality(city) Z organization Q organization-unit T scep-password-string 57E6CA35452E72E4D1BC4518260ABFC7 scep-url http://0.0.0.0/X/Y/ state(province) s
我认为线路本身没有问题(因为它不会在我的虚拟机上崩溃)。尝试将其打印到文件而不是屏幕时,它不会崩溃:
for (std::vector<std::string>::iterator it = lines_vector.begin(); it != lines_vector.end(); ++it){
sprintf(tmp, "echo \"%s\" >> /X/Y/Z.txt", (*it).c_str());
OS_run(tmp); // run this command on sh shell
}
由于它仅在我的嵌入式而不是我的 VM 上崩溃,我认为该文件以某种方式损坏。可能是字符串内部有一个无效的字符会崩溃fprintf
,但不是echo
吗?
我尝试将这段代码翻译成正确的 C++,但我仍然在最后一个字符串的中间崩溃。我知道混合 C/C++ 不好,但不应该是和 char *c_str()
之间的正确接口(期望)?std::string
fprintf
如果不是这样,那么在此期间可能会发生什么崩溃fprintf
?
int main()
{
std::vector<std::string> lines_vector;
std::ifstream infile(in_file);
std::string line;
int counter = 1;
while (std::getline(infile, line)) {
if (line.find(keyword, 0) != std::string::npos) {
lines_vector.push_back(line);
for(int lines_to_copy = 2; lines_to_copy > 0; lines_to_copy--) {
std::getline(infile, line);
lines_vector.push_back(line);
}
}
}
for (std::vector<std::string>::iterator it = lines_vector.begin(); it != lines_vector.end(); ++it){
fprintf(stdout, "%d)%s", counter++, (*it).c_str());
}
}
解决方案
在嵌入式设备上,您可以预期动态内存分配会失败。这意味着您绝对必须控制所有可能的分配(即使在非嵌入式设备上您也应该控制,但崩溃风险要低得多......)。你真的应该有:
while ((num_bytes_read = getline(&line, &len, fp)) != -1) {
...
}
if (line == NULL) {
perror("getline could not allocate buffer");
}
这不会解决任何问题,但至少你会知道会发生什么。
我在这里尊重您的编码风格,大量使用 C 库并使用goto
. 但我必须建议你不要在 C++ 程序中这样做。
C 库曾经包含在 C++ 标准库中,因为早期的 C++ 实现缺乏太多功能。在现代 C++goto
中,所有原始 C 字符串和 C io 函数都将被禁止(非常特殊的用例除外)。并且 C++ 带有一个版本getline
(在 header 中<string>
),它直接填充一个std::string
. 如果学习 C++,你真的应该尽量避免 C 构造。
根据 Ben Voigt 的评论,如果您想避免动态分配,有正确的用例可以使用旧式 C 库。但在这种情况下,你也应该避免std::string
和std::vector
推荐阅读
- c# - 简化 HTMLAgilitypack 文档中的 Linq 搜索
- node.js - 如何修复 NodeJS 中的“无法读取未定义的属性“发出”错误
- javascript - 使用 JavaScript 拆分逗号分隔的字符串但忽略分号之间的逗号
- javascript - 从正则表达式中删除子正则表达式查询
- java - Windows 是否有唯一的密钥/指纹,重新安装后不会消失?
- visual-studio-extensions - 扩展 Visual Studio 以环绕外部提供程序
- python - Python中只需要显示一个itertools计算列表的当前元素
- reactjs - 如何修复在 Select 中不显示任何值的错误,我可以单击它并获取最后一个对象
- javascript - 在 AFrame 中创建沉淀
- php - 从数组中仅获取一个值(php)