fprintf 在特定字符串上失败,而 shell 函数使用它没有崩溃

fprintf fails on specific string while shell functions use it with no crash

简短版本:我有一个 C++ 代码,它使用 C 调用 fprintf(stdout, some_cpp_str.c_str()) 并在调用期间崩溃。前 4 次调用都很好,只有第 5 次崩溃,我不知道为什么 (怀疑字符串中有不可读的字符)。我发布的第一个代码主要是 C,所以我发布了另一个代码,除了 fprintf (代码添加在问题的底部)之外只有 C++。崩溃(始终)发生在嵌入式设备上。在我自己的电脑上,代码 运行s fine


长版:

我有一个代码可以从文本中读取行,并将它们推送到一个字符串向量中。为了检查我的进度,我还在矢量填充后 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;
}

这在我的 VM 上运行良好,但我也在嵌入式设备上 运行 它,它总是在特定线路上崩溃。该行是:

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

我认为线路本身没有问题(因为它不会在我的 VM 上崩溃)。尝试将其打印到文件而不是屏幕时,它不会崩溃:

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++ 不好,但 c_str() 不应该是 std::string 和 char * (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::stringstd::vector