努力构建便携式代码以使用C在任何操作系统中生成文件

发布于 2025-02-02 16:48:24 字数 3136 浏览 2 评论 0 原文

我正在尝试构建一个C Portable代码(用于Windows,MacOS和Linux),该代码创建输出 .txt 文件以接收数值模拟的结果。

总而言之,该代码以文件的名称和扩展名称,并检查该文件是否已经存在于目录中。如果是这样,它将创建另一个具有相同名称的文件,但最终在括号(#)之间有一个数字,以区分旧的旧文件。

问题是:它在MAC环境上正常工作,但是当我在Windows上编译并运行它时,该文件并未在执行结束时创建。我找不到我在做错什么。

另外,我正在使用 Intel C/C ++经典编译器。如果我使用另一个编译器,例如,Windows的intel®Oneapidpc ++/C ++编译器 ,它会抱怨 sizef(src)当我调用 > strncat(...)函数。

到目前为止,这是代码的版本:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

bool file_exists(char *filename);
FILE *create_output_file(char *name, char *ext, bool (*file_exists)(char *));

#define funcname "test"

int main(void) {
    
    // Create output files to store results
    char *output_filename = malloc(200 * sizeof(*output_filename));
    sprintf(output_filename, "%s_out", funcname);
    printf("output_filename = %s\n", output_filename);
    char *ext = ".txt";
    FILE *output_file = create_output_file(output_filename, ext, file_exists);
}

bool file_exists(char *filename) {
    // Try to open file with same name as filename
    FILE *testfile = fopen(filename, "r");
    // Bool variable to check the existence of file
    bool exists = false; 
    // Check the existence of a file called filename
    if (testfile != NULL) {
        // Returns true if the file exists
        exists = true; 
    }
    // Close the file
    fclose(testfile); 
    // Returns the existence of a file (1) = does exist, (0) = does not exist
    return exists;
}

FILE *create_output_file(char *name, char *ext, bool (*file_exists)(char *)) {
    // Form the full filename
    name = strncat(name, ext, sizeof(ext));
    printf("fullfilename = %s\n", name);
    // Check if a file with the filename exists in the directory
    if (file_exists(name)) {
        // If exists, assign the same name with "(number)" to differentiate the new version
        int j = 1;
        char *numb = malloc(10 * sizeof(*numb));
        sprintf(numb, "(%i)", j);
        // Remove the extension from the name string
        name[strlen(name) - strlen(ext)] = '\0';
        // Add (number) to the name and then add the file extension again
        name = strncat(name, numb, sizeof(numb));
        name = strncat(name, ext, sizeof(ext));
        // Check if the name with numbers exists until it doesn't
        int limit = 1e1;
        while (file_exists(name)) {
            j++;
            sprintf(numb, "(%i)", j);            
            if (j == limit) {
                name[strlen(name) - strlen(numb) + 1 - strlen(ext)] = '\0';
                limit = limit*10;    
            } else {
                name[strlen(name) - strlen(numb) - strlen(ext)] = '\0';
            }
            name = strncat(name, numb, sizeof(numb));
            name = strncat(name, ext, sizeof(ext));
        }
        // Free allocated memory
        free(numb); 
    }
    // After assign the proper name, create the output file
    FILE *output_file = fopen(name, "w");
    // Returns the file
    return output_file;
}

我在这里缺少什么?

I'm trying to build a C portable code (for Windows, MacOS and Linux) that creates an output .txt file to receive the results of a numerical simulation.

Summarizing, the code takes the name of the file and the extension and checks if the file already exists in the directory. If so, it creates another file with the same name, but with a number between parenthesis (#) in the end to distinguish the old from the new one.

The problem is: it is working properly on the mac environment, however when I compile and run it on windows, the file is not created in the end of execution. I could not find what I'm doing wrong.

Also, I'm using Intel C/C++ Classic compiler. If I use another compiler, for example, the Intel® oneAPI DPC++/C++ Compiler for windows, it complains about the usage of sizeof(src) when I call the strncat(...) function.

So far, this is the version of the code:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

bool file_exists(char *filename);
FILE *create_output_file(char *name, char *ext, bool (*file_exists)(char *));

#define funcname "test"

int main(void) {
    
    // Create output files to store results
    char *output_filename = malloc(200 * sizeof(*output_filename));
    sprintf(output_filename, "%s_out", funcname);
    printf("output_filename = %s\n", output_filename);
    char *ext = ".txt";
    FILE *output_file = create_output_file(output_filename, ext, file_exists);
}

bool file_exists(char *filename) {
    // Try to open file with same name as filename
    FILE *testfile = fopen(filename, "r");
    // Bool variable to check the existence of file
    bool exists = false; 
    // Check the existence of a file called filename
    if (testfile != NULL) {
        // Returns true if the file exists
        exists = true; 
    }
    // Close the file
    fclose(testfile); 
    // Returns the existence of a file (1) = does exist, (0) = does not exist
    return exists;
}

FILE *create_output_file(char *name, char *ext, bool (*file_exists)(char *)) {
    // Form the full filename
    name = strncat(name, ext, sizeof(ext));
    printf("fullfilename = %s\n", name);
    // Check if a file with the filename exists in the directory
    if (file_exists(name)) {
        // If exists, assign the same name with "(number)" to differentiate the new version
        int j = 1;
        char *numb = malloc(10 * sizeof(*numb));
        sprintf(numb, "(%i)", j);
        // Remove the extension from the name string
        name[strlen(name) - strlen(ext)] = '\0';
        // Add (number) to the name and then add the file extension again
        name = strncat(name, numb, sizeof(numb));
        name = strncat(name, ext, sizeof(ext));
        // Check if the name with numbers exists until it doesn't
        int limit = 1e1;
        while (file_exists(name)) {
            j++;
            sprintf(numb, "(%i)", j);            
            if (j == limit) {
                name[strlen(name) - strlen(numb) + 1 - strlen(ext)] = '\0';
                limit = limit*10;    
            } else {
                name[strlen(name) - strlen(numb) - strlen(ext)] = '\0';
            }
            name = strncat(name, numb, sizeof(numb));
            name = strncat(name, ext, sizeof(ext));
        }
        // Free allocated memory
        free(numb); 
    }
    // After assign the proper name, create the output file
    FILE *output_file = fopen(name, "w");
    // Returns the file
    return output_file;
}

What am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

所有深爱都是秘密 2025-02-09 16:48:24

有多个问题:

  • file_exists 您调用 fclose(testfile)即使 fopen 失败了,这也没有定义。

  • create_output_file 中,您对 sizeof 的用法不正确:in strncat(name,ext,ext,sizeof(ext)); SizeOf 应用于指针,因此将其评估为指针的大小,而不是其指向的字符串的长度。您可以写

      strncat(name,ext,strlen(ext));
     

    ,但这完全等同于 strcat(name,ext);

    功能 strncat 定义为

      char *strncat(char *dest,const char *src,size_t n);
     

    它最多复制 n 字符以及从字符串指向 src 的null终结器,在字符串末尾指向 dest> dest 。


  • 代码太复杂了,您有多个内存泄漏,并且在撰写文件名时不会检查缓冲区溢出。

这是一个简化的版本:

#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define funcname "test"

bool file_exists(const char *filename) {
    // Try to open file with same name as filename
    FILE *testfile = fopen(filename, "r");
    if (testfile != NULL) {
        fclose(testfile);
        return true;
    } else {
        return false;
    }
}

#define MAX_FILE_NUM  10000

FILE *create_output_file(char *name, size_t size,
                         const char *ext,
                         bool (*file_exists)(const char *))
{
    size_t len = strlen(name);
    int i = 0;

    snprintf(name + len, size - len, "%s", ext);
    while (file_exists(name)) {
        if (++i > MAX_FILE_NUM) {
            // all file versions tried.
            return NULL;
        }
        snprintf(name + len, size - len, "(%d)%s", i, ext);
    }
    return fopen(name, "w");
}

int main() {
    // Create output files to store results
    char output_filename[200];
    snprintf(output_filename, sizeof output_filename, "%s_out", funcname);
    printf("output_filename = %s\n", output_filename);
    const char *ext = ".txt";
    FILE *output_file = create_output_file(output_filename,
                            sizeof output_filename, ext, file_exists);
    if (output_file == NULL) {
        printf("could not open output file, last try: %s\n", output_filename);
    } else {
        printf("actual output_filename = %s\n", output_filename);
        fclose(output_file);
    }
    return 0;
}

There are multiple problems:

  • In file_exists you call fclose(testfile) even if fopen failed This has undefined behavior.

  • in create_output_file , your usage of sizeof is incorrect: in strncat(name, ext, sizeof(ext)); sizeof is applied to a pointer, hence it evaluates to the size of a pointer, not the length of the string it points to. You could write

    strncat(name, ext, strlen(ext));
    

    but it would be exactly equivalent to strcat(name, ext);

    The function strncat is defined as

      char *strncat(char *dest, const char *src, size_t n);
    

    it copies at most n characters plus a null terminator from the string pointed to by src at the end of the string pointed to by dest.

  • The code is too complicated, you have multiple memory leaks and you do not check for buffer overflow when composing the filename.

Here is a simplified version:

#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define funcname "test"

bool file_exists(const char *filename) {
    // Try to open file with same name as filename
    FILE *testfile = fopen(filename, "r");
    if (testfile != NULL) {
        fclose(testfile);
        return true;
    } else {
        return false;
    }
}

#define MAX_FILE_NUM  10000

FILE *create_output_file(char *name, size_t size,
                         const char *ext,
                         bool (*file_exists)(const char *))
{
    size_t len = strlen(name);
    int i = 0;

    snprintf(name + len, size - len, "%s", ext);
    while (file_exists(name)) {
        if (++i > MAX_FILE_NUM) {
            // all file versions tried.
            return NULL;
        }
        snprintf(name + len, size - len, "(%d)%s", i, ext);
    }
    return fopen(name, "w");
}

int main() {
    // Create output files to store results
    char output_filename[200];
    snprintf(output_filename, sizeof output_filename, "%s_out", funcname);
    printf("output_filename = %s\n", output_filename);
    const char *ext = ".txt";
    FILE *output_file = create_output_file(output_filename,
                            sizeof output_filename, ext, file_exists);
    if (output_file == NULL) {
        printf("could not open output file, last try: %s\n", output_filename);
    } else {
        printf("actual output_filename = %s\n", output_filename);
        fclose(output_file);
    }
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文