Jan
Jan

Reputation: 11726

Initialise a variable to its own undefined value

In C, does initialising a variable to it's own value make sense? If yes, what for?

Allow me to elaborate. In Git sources there are some examples of initialising a variable to it's own undefined value, as seen in transport.c or wt-status.c. I removed assignments from those declarations and run tests. Seeing no regressions, I thought that those assignments were redundant.

On the other hand, I did some simple tests with GCC 4.6 and Clang 2.9.

#include <stdio.h>
int main() {
  printf("print to increase probability of registers being non-zero\n");
  int status = status;
  return printf("%i\n", status);
}

Compiling with -Wall -std=c99 and various -O levels prints no warnings and shows that status == 0. Clang with a non-zero optimisation level prints some garbage values though. It makes me infer that results of such expressions are undefined.

I can imagine that such assignment can suppress an uninitialised variable warning, but it's not the case for the examples taken from Git. Removing assignments doesn't introduce any warnings.

Are such assignments an undefined behaviour? If not, what do you use them for?


I've suggested the change on the Git mailing list. Here's what I've learned.

Upvotes: 21

Views: 2220

Answers (4)

Alok Save
Alok Save

Reputation: 206596

This compiles because Standard C99 §6.2.1/7 says:

Any identifier that is not a structure, union, or enumeration tag "has scope that begins just after the completion of its declarator." The declarator is followed by the initializer.

However, value of status is Indeterminate. And you cannot rely on it being initialized to something meaningful.

How does it work?
int status creates an space for the variable to exist on the stack(local storage) which is then further read to perform status = status, status might get initialized to any value that was present in the stack frame.

How can you guard against such self Initialization?
gcc provides a specific setting to detect self Initializations and report them as errors:

-Werror=uninitialized -Winit-self

Why is it used in this code?
The only reason I can think it is being used in the said code is to suppress the unused variable warning for ex: In transport.c, if the control never goes inside the while loop then in that control flow cmp will be unused and the compiler must be generating a warning for it. Same scenario seems to be with status variable in wt-status.c

Upvotes: 11

Violet Giraffe
Violet Giraffe

Reputation: 33607

I think status = status doesn't change the value of status (compared to int status;). I think it is used to suppress the unused variable warning.

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754710

On MacOS X 10.7.2, I tried this example - with the result shown...

$ cat x3.c
#include <stdio.h>

int status = -7;

int main()
{
    printf("status = %d\n", status);
    int status = status;
    printf("status = %d\n", status);
    return 0;
}
$ make x3
gcc -O -std=c99 -Wall -Wextra  x3.c -o x3  
$ ./x3
status = -7
status = 1787486824
$

The stack space where the local status in main() has been used by printf() so the self-initialization copies garbage around.

Upvotes: 1

For me the only reason of such self-assigning initialization is to avoid a warning.

In the case of your transport.c, I don't even understand why it is useful. I would have left cmp uninitialized.

My own habit (at least in C) is to initialize all the variables, usually to 0. The compiler will optimize unneeded initialization, and having all variables initialized makes debugging easier.

There is a case when I want a variable to remain uninitialized, and I might self-assign it: random seeds:

 unsigned myseed = myseed;
 srand(myseed);

Upvotes: 1

Related Questions