views:

90

answers:

5

is there an advantage in one of the following two approaches over the other?

here it is first tested, whether fopen succeeds at all and then all the variable declarations take place, to ensure they are not carried out, since they mustn't have had to

void func(void) {
    FILE *fd;

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    int a, b, c;
    float d, e, f;
    /* variable declarations */

    /* remaining code */
}

this is just the opposite. all variable declarations take place, even if fopen fails

void func(void) {
    FILE *fd;
    int a, b, c;
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */        
}

does the second approach produce any additional cost, when fopen fails? would love to hear your thoughts!

+1  A: 

When fopen fails, the application exits, so nobody really cares if the variables were initialized. There is no cost, because the application has already terminated and the statically allocated memory already freed. As mentioned, the memory isn't even allocated, but it would have if you had set all of them to a default value, like 0. Even if you change this behavior, there is no additional cost.

Also, the second code is probably preferable because it is C89 compliant.

mathepic
so it doesn't take up any additional time, for the variables that have been initialized for nothing?
guest
Variable initialization is for the compiler, not the binary.
mathepic
what if i had instead of `int a` `int i, a[10000]; for(i=0; i<10000; i++) a[i] = i;`? would *that* make a difference?
guest
Of course iterating through an array takes time, but where you declare the variables makes no difference no matter how "big" they are.
Ronny Vindenes
Well, declaring 10,000 variables before exiting and assigning them a value will of course make a difference in time. However, it takes almost no time to do "int a = 0;". Then, when you exit, the memory is freed so there is no cost.
mathepic
+1 for pointing out the C89 compliance issue - only C99 and gcc extensions allow for C++-style interleaving of variable definitions and statements - for maximum portability it's best to avoid this (e.g. if you ever want the code to compile with MSVC).
Paul R
+3  A: 

No, it doesn't have any cost. Both examples most likely compile to the same resulting binary. Since variable declaration without assignment doesn't actually do anything in C, it doesn't generate any code. The space available for those variables will be simply skipped over by the stack pointer when needed.

viraptor
A: 

Stack variable allocation for all variables in the function in the same scope likely happens at the top of your function in both cases, so either method is fine.

Brian R. Bondy
A: 

It shouldn't make any difference, but you can always compare the assembly output of the two versions to make sure!

Space on the stack is always prepared on function entry, probably in order to get a nice function mapping variable names to base pointer + offset for the compiler/compiler writer. As for initialization, it shouldn't make any difference either. The content is undefined until something is written into the variables in both versions.

In C++ however, you might get into some problems when jumping past initialization (which you aren't doing in the code in your example), but C++ is much more complicated to reason about.

fl3x
+1  A: 

The variable declarations in your example would not cost extra with most compilers. The only time they might is if they had initialization values which required any non-trivial code to produce.

For example:

void func(const char * filename) {
    FILE *fd;
    int a, b, c;
    size_t z = strlen(filename);
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen(filename, "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */    
    /* Some code that uses z */
}

In this example strlen may be called before the attempt to open the file but it's value never used. Placing the call to strlen after the fopen could result in better code. This isn't really the best example though, because compilers often know that several functions like strlen are purely functional (no side effects and only use their arguments to produce results) and could move the call to strlen below the fopen itself, but you should get the idea.

nategoose