首页 > 解决方案 > 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::stringfprintf

如果不是这样,那么在此期间可能会发生什么崩溃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());
    }
}

标签: c++printfecho

解决方案


在嵌入式设备上,您可以预期动态内存分配会失败。这意味着您绝对必须控制所有可能的分配(即使在非嵌入式设备上您也应该控制,但崩溃风险要低得多......)。你真的应该有:

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::stringstd::vector


推荐阅读