0

I have a task and I need your advice

I run my program with arguments, like

./program.x input.txt output.txt

So in my program I check that I use properly arguments

    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source result\n",argv[0]);
    exit(1);
    }

    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }

    if( (wc= fopen(argv[2],"w")) == NULL) {
        printf("Open error %s\n", argv[2]);
        exit(2);
    }

I also use assert to check that file is ok, they told us that we must use assert too

    assert((wz = fopen(argv[1] ,"r")));
    assert((wc = fopen(argv[2] ,"w")));

But I dont know I should first put assert, or first checking number of arguments?

    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source result\n",argv[0]);
    exit(1);
    }

    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }

    if( (wc= fopen(argv[2],"w")) == NULL) {
        printf("Open error %s\n", argv[2]);
        exit(2);
    }
    assert((wz = fopen(argv[1] ,"r")));
    assert((wc = fopen(argv[2] ,"w")));

or

    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source result\n",argv[0]);
    exit(1);
    }

    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }

    if( (wc= fopen(argv[2],"w")) == NULL) {
        printf("Open error %s\n", argv[2]);
        exit(2);
    }
    assert((wz = fopen(argv[1] ,"r")));
    assert((wc = fopen(argv[2] ,"w")));
    if (argc != 3) {                                
    printf("Wrong arguments number\n");
    printf("I should run this way:\n");
    printf("%s source result\n",argv[0]);
    exit(1);
    }

    if( (wz= fopen(argv[1],"r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }

    if( (wc= fopen(argv[2],"w")) == NULL) {
        printf("Open error %s\n", argv[2]);
        exit(2);
    }
Jakub
  • 679
  • 5
  • 16
  • 2
    Do not use `assert` with `fopen`. – KamilCuk May 01 '20 at 13:00
  • 3
    You should not call `assert` with any expression that has side effects, because it won't generate any code at all if the `NDEBUG` macro is defined. – Ian Abbott May 01 '20 at 13:03
  • 2
    Generally asserts are for debug builds, so you should not use them for flow control in your actual program... that is a tradition that you can break because it requires compiling with the macro NDEBUG for release build ... but the fact that they are conditionally ignored means you should not use them for business logic, it will bite you somewhere down the road. – Grady Player May 01 '20 at 13:03

1 Answers1

1

assert(expression) is a macro defined by #include <assert.h>.

If the NDEBUG macro is defined before the #include <assert.h> line then the macro call assert(expression) expands to the void expression ((void)0). Otherwise, it will write an error message to the standard error stream and call abort().

Because assert(expression) might not generate any code, it should not be called if the expression has any side effects. One example of a side effect is assigning a value to a variable (or other lvalue). Another example of a side effect is opening file. The call assert((wz = fopen(argv[1] ,"r"))); does both of those things. The correct way to use assert in this case, is to do perform the operation before the assert call and only use assert to check the result. For example:

wz = fopen(argv[1], "r");
assert(wz != NULL);

The expression wz != NULL has no side effects (assuming wz has not been declared with the volatile type qualifier), so is safe.


OP is using assert as part of an exercise. It should be noted that assert is typically used only to check things that are not expected to fail, and the message it writes to the standard error stream is meant to help the developer discover bugs in the code. However, calling fopen on a command line argument is something that is quite likely to fail, and should normally be handled in a way that is useful to the user of the program, rather than the developer.

Ian Abbott
  • 15,083
  • 19
  • 33