Thread: Using argc without argv. (-Wfatal-errors)

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    120

    Using argc without argv. (-Wfatal-errors)

    Hi,

    I'm starting to notice how much I reuse certain code. For instance, this is a common `test` in many of my programs:
    Code:
    if(SOME_TEST == FAILED)
    {
        fprintf(stderr, "%s: FUNCTION_NAME error: LAST_COMMAND failed (%s)\n", program_name, strerror(errno));
        exit(EXIT_FAILURE);
    }
    I recently learned about some gcc variables, namely `program_invocation_short_name` which give the basename of the called program, and `__func__` which gives the name of the called function.

    Now, `program_invocation_short_name` is useful to me as in the main function of every program, I do the following to get the program name (`program_name` being a global variable):
    Code:
    int main (int argc, char *argv[])
    {
    // Get program name for error reporting.
        strcpy(program_name, basename(argv[0]));
    
    // Check number of arguments.
        if(argc != 1)
        {
            fprintf(stderr, "Usage: %s\n", program_name);
            exit(EXIT_FAILURE);
        }
    
    // Run process.
        run_process();
    
    // Exit cleanly.
        exit(EXIT_SUCCESS);
    }
    So using `program_invocation_short_name` stops me from having a global variable and I don't have to load `libgen.h`. The problem I'm running into is needing to test the number of variables from the command line, but no longer needed any of the `argv` arguments.

    I also try to program with a lot of gcc flags to make my programming better. But the `-Wfatal-errors` flag won't allow unused variables. If I don't use `basename(argv[0])` to get the program name, the compiler complains that `argv` is unused. If I try to remove just the `argv` declaration from the main function, then gcc complains with a lie to me:
    Code:
    dea_template.c:28:5: error: ‘main’ takes only zero or two arguments [-Werror=mai
       28 | int main (int argc)
          |     ^~~~
    compilation terminated due to -Wfatal-errors.
    cc1: all warnings being treated as errors
    I say that what gcc reports is a lie, because the following generates zero errors:
    Code:
    int main(int argc, char * argv[], char *envp[])
    So is there a way to stop the compiler from complaining without removing the `-Wfatal-errors` flag or by adding:
    Code:
    if(argv[0])
        {;}
    ? My ultimate goal is to try to make my `tests` into a macro to reduce the clutter of my programs.
    Last edited by Yonut; 07-15-2020 at 11:12 AM. Reason: Fixed code.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    How about
    Code:
    strcpy(program_name, argc ? basename(argv[0]) : "");
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,630
    If you want to ignore a parameter:
    Code:
    #include <stdio.h>
     
    int main(int argc, char **argv) {
        (void)argv;
        printf("%d\n", argc);
        return 0;
    }
    Or perhaps:
    Code:
    #include <stdio.h>
     
    #define UNUSED(x) (void)(x)
     
    int main(int argc, char **argv) {
        UNUSED(argv);
        printf("%d\n", argc);
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    Registered User
    Join Date
    Apr 2019
    Posts
    120
    Quote Originally Posted by Salem View Post
    How about
    Code:
    strcpy(program_name, argc ? basename(argv[0]) : "");
    I feel I might not have been as clear as I could have. I always test for the number of command line arguments because I don't like misusing one of my programs. If a program takes no arguments, I don't want someone being able to invoke it with arguments.


    Quote Originally Posted by john.c View Post
    If you want to ignore a parameter:
    Code:
    #include <stdio.h>
     
    int main(int argc, char **argv) {
        (void)argv;
        printf("%d\n", argc);
        return 0;
    }
    That is so perfect, ty. Although this only helps in this one scenario, I can see myself using this for debugging.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Yonut
    But the `-Wfatal-errors` flag won't allow unused variables.
    Not quite: -Wfatal-errors "causes the compiler to abort compilation on the first error occurred rather than trying to keep going and printing further error messages". What you're thinking of is -Wunused-parameter, which you probably enabled by using -Wextra with -Wall.

    Quote Originally Posted by Yonut
    I recently learned about some gcc variables, namely `program_invocation_short_name` which give the basename of the called program, and `__func__` which gives the name of the called function.
    __func__ is part of the C standard, so you can freely use it in portable code.

    Incidentally, if you intend to use compiler-specific stuff, then there's another option for declaring that a variable is meant to be possibly unused:
    Code:
    int main(int argc, char *argv[] __attribute__((unused)))
    This is good because it explicitly documents the parameter as unused, but if you're trying to write portable code then john.c's suggestion of using void is better: the macro version might be overkill especially if only used once; a comment will do in case someone hasn't seen this method of suppressing a possible compile warning/error.
    Last edited by laserlight; 07-15-2020 at 04:44 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Apr 2019
    Posts
    120
    Quote Originally Posted by laserlight View Post
    Not quite: -Wfatal-errors "causes the compiler to abort compilation on the first error occurred rather than trying to keep going and printing further error messages". What you're thinking of is -Wunused-parameter, which you probably enabled by using -Wextra with -Wall.
    You're right, I just used what was reported from the compiler without giving any thought to the flags I use.
    Code:
    compilation terminated due to -Wfatal-errors.
    For the record, I always use the following command with gcc (adding extra flags/libraries when needed):

    Code:
    gcc -Wall -Werror -Wextra -Wfatal-errors -D_GNU_SOURCE -O3 -o PROGRAM_NAME PROGRAM_CODE.c
    Quote Originally Posted by laserlight View Post
    Incidentally, if you intend to use compiler-specific stuff, then there's another option for declaring that a variable is meant to be possibly unused:
    Code:
    int main(int argc, char *argv[] __attribute__((unused)))
    This is good because it explicitly documents the parameter as unused, but if you're trying to write portable code then john.c's suggestion of using void is better: the macro version might be overkill especially if only used once; a comment will do in case someone hasn't seen this method of suppressing a possible compile warning/error.
    Tyvm, I like this better as the other method I raved at before, was just a more compact form of:
    Code:
    if(argv[0])
        {;}
    I didn't realize right away that it was another useless command to quite the compiler. I also don't write anything for other platforms, too long to get into here as to why.

  7. #7
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    On a tangent and just out of interest, given:
    Code:
    int main (int argc, char *argv[])
    
    {
    // Get program name for error reporting.
    
        strcpy(program_name, basename(argv[0]));
    What happens if argc == 0 (and argv[0] is therefore NULL; i.e. is it ok to pass NULL as the src pointer for strcpy)?

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Hodor View Post
    On a tangent and just out of interest, given:
    Code:
    int main (int argc, char *argv[])
    
    {
    // Get program name for error reporting.
    
        strcpy(program_name, basename(argv[0]));
    What happens if argc == 0 (and argv[0] is therefore NULL; i.e. is it ok to pass NULL as the src pointer for strcpy)?
    I'd say that the behaviour is undefined, and it would likely happen with the call to basename first rather than to strcpy.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Apr 2019
    Posts
    120
    Quote Originally Posted by Hodor View Post
    On a tangent and just out of interest, given:
    Code:
    int main (int argc, char *argv[])
    
    {
    // Get program name for error reporting.
    
        strcpy(program_name, basename(argv[0]));
    What happens if argc == 0 (and argv[0] is therefore NULL; i.e. is it ok to pass NULL as the src pointer for strcpy)?
    I have no idea how to invoke a program without using it's filename. It's my understanding that argv[0], when declared in the main function header, will always contain the program filename.
    Last edited by Yonut; 07-15-2020 at 08:44 PM.

  10. #10
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by Yonut View Post
    I have no idea how to invoke a program without using it's filename. It's my understanding that argv[0], when declared in the main function header, will always contain the program filename.
    I concede that if you run the program on a modern desktop OS then, yes, it's very unlikely that argc will be 0, but the C standard allows for it to be 0 (and if it's 0 then argv[0] will be NULL). That said I think it's worth remembering that it might be 0

    Edit: I don't have a copy of the C standard handy but I think (only think, I'm not 100% positive) that even if argc is > 0 argv[0] can be an empty string (not NULL as the case is when argc == 0, but "\0") if the program name is for whatever reason not available... but an empty string is much less likely to cause issues compared to it being NULL and assuming that it's not
    Last edited by Hodor; 07-15-2020 at 09:06 PM.

  11. #11
    Registered User
    Join Date
    Dec 2017
    Posts
    1,630
    Page 13 of N1570 says

    If the value of argc is greater than zero, the string pointed to by argv[0]
    represents the program name; argv[0][0] shall be the null character if the
    program name is not available from the host environment.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  12. #12
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by john.c View Post
    Page 13 of N1570 says
    Thanks.

    For completeness (to cover the case of argc == 0 amongst other things)
    argv[argc]shall be a null pointer

    So argv[0] might be a NULL pointer if argc == 0 and might be an empty string if argc > 0 (argv[0][0] == '\0'). The case of it pointing to an empty string made sense about two seconds after I made the edit in my previous comment but I left the edit because I didn't have the standard handy. Thanks for the link

  13. #13
    Registered User
    Join Date
    Apr 2019
    Posts
    120
    Ty all, this has been interesting.

  14. #14
    Registered User
    Join Date
    Apr 2019
    Posts
    120
    Quote Originally Posted by Salem View Post
    How about
    Code:
    strcpy(program_name, argc ? basename(argv[0]) : "");
    Wow Salem, it's like you can see into the future. I shouldn't have writen off your comment so quickly. I now use the following for my main function template:

    Code:
    int main (int argc, char *argv[] __attribute__((unused)))
    {
    // Check number of arguments.
        if(argc != 1)
        {
            fprintf(stderr, "Usage: %s\n", argc ? program_invocation_short_name : "");
            exit(EXIT_FAILURE);
        }
    
    // Run process.
        run_process();
    
    // Exit cleanly.
        exit(EXIT_SUCCESS);
    }
    Ty.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. argv and argc
    By antros48 in forum C Programming
    Replies: 19
    Last Post: 09-30-2011, 08:26 AM
  2. argc, argv
    By Martas in forum C Programming
    Replies: 6
    Last Post: 11-19-2009, 09:39 AM
  3. argc, **argv in C++.
    By apacz in forum C++ Programming
    Replies: 8
    Last Post: 01-05-2007, 12:09 AM
  4. argc & argv
    By miryellis in forum C Programming
    Replies: 11
    Last Post: 09-19-2004, 11:59 PM
  5. how do i? re: argc - argv
    By luigi40 in forum C Programming
    Replies: 2
    Last Post: 06-11-2004, 10:17 AM

Tags for this Thread