-1

What is the best way to build the absolute path to the file and then create a directory and a file? I have found the following method. Could you please review it, or suggest something better?

char *pub_working_dir, *pub_results_dir, *pub_path_file;

pub_working_dir=(char *)calloc(256, sizeof(char));

if (pub_working_dir) buffer=_getcwd(pub_working_dir, 256);

if (buffer!=NULL) 
{
    pub_results_dir=(char *)calloc(256, sizeof(char));
    if (pub_results_dir)
    {
        sprintf_s(pub_results_dir, 256, "%s\\results", pub_working_dir);
        _mkdir(pub_results_dir);
        pub_path_file=(char *)calloc(256, sizeof(char));
        if (pub_path_file)
        {
            sprintf_s(pub_path_file, 256, "%s\\file.txt", pub_results_dir);
            FILE *file;
            int err_fp = fopen_s(&file, pub_path_file, "a");
            if (err_fp==0) 
            {
                // write to the file
                fclose(file);
            }
        }
    }
}

EDIT: I am looking for the fastest and most readable method purposed to work with Visual Studio 2022 Compiler on Windows.

SerTet
  • 29
  • 6

1 Answers1

1

I am looking for the fastest and most readable method purposed to work with Visual Studio 2022 Compiler on Windows.

  • calloc is slower than malloc since it performs zero initialization. If you don't actually need zero initialization, then don't use calloc.

  • Dynamic allocation is always slower than static allocation. You could swap out all those buffers for static or local storage instead.

  • Using printf family of functions for string handling is needlessly slow. You seem to use it solely for the purpose of string concatenation, but in this case a simple strcat would work instead.

  • However strcat and similar are also slow because they iterate through the string yet again. After taking the strings as input, you can call strlen to learn their lengths. And from there on you don't need to look for null terminators yet again. For example:

    memcpy(&str[length], "\\file.txt", sizeof("\\file.txt"));

    (Note that sizeof includes the null terminator of the string literal, so it will get copied too.)
    This has superior performance to the stdio.h bloat functions as well as strcat.

  • The various _s functions of MSVC may or may not follow the C standard and may or may not give increased safety. What they no doubt do is to increase execution overhead, because in order to be safe they need additional error checks.

    For example Microsoft loves to check if everyone and their mother are equal to NULL, which adds extra branches as pointless bloat. Because I can tell them for sure that my string literals do not equal NULL - in fact they are not even user input so applying "secure" functions on them is nonsense.

    I'd recommend to drop anything called _s unless both you and Microsoft can give a clear rationale exactly why the _s flavour would lead to increased security in your use-case.

  • Regarding the most readable method, consider making a function that immediately returns an error code such as an enum, upon error. You keep increasing the nesting/indention for every error check, which makes the code much harder to read. Instead do along the lines of:

    if (pub_working_dir == NULL)
       return MYFUNC_ERR_MEMALLOC;
    ...
    if (buffer==NULL) 
       return MYFUNC_ERR_GETCWD;
    ...
    if (err_fp!=0) 
       return MYFUNC_ERR_FILENOTFOUND;
    

    Getting rid of all the nesting drastically helps readability. However, upon errors don't forget to clean up any resources you have allocated or opened!

Lundin
  • 195,001
  • 40
  • 254
  • 396