Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
641 views
in Technique[技术] by (71.8m points)

undefined - A question about union in C - store as one type and read as another - is it implementation defined?

I was reading about union in C from K&R, as far as I understood, a single variable in union can hold any one of the several types and if something is stored as one type and extracted as another the result is purely implementation defined.

Now please check this code snippet:

#include<stdio.h>

int main(void)
{
  union a
  {
     int i;
     char ch[2];
  };

  union a u;
  u.ch[0] = 3;
  u.ch[1] = 2;

  printf("%d %d %d
", u.ch[0], u.ch[1], u.i);

  return 0;
}

Output:

3 2 515

Here I am assigning values in the u.ch but retrieving from both u.ch and u.i. Is it implementation defined? Or am I doing something really silly?

I know it may seem very beginner to most of other people but I am unable to figure out the reason behind that output.

Thanks.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is undefined behaviour. u.i and u.ch are located at the same memory address. So, the result of writing into one and reading from the other depends on the compiler, platform, architecture, and sometimes even compiler's optimization level. Therefore the output for u.i may not always be 515.

Example

For example gcc on my machine produces two different answers for -O0 and -O2.

  1. Because my machine has 32-bit little-endian architecture, with -O0 I end up with two least significant bytes initialized to 2 and 3, two most significant bytes are uninitialized. So the union's memory looks like this: {3, 2, garbage, garbage}

    Hence I get the output similar to 3 2 -1216937469.

  2. With -O2, I get the output of 3 2 515 like you do, which makes union memory {3, 2, 0, 0}. What happens is that gcc optimizes the call to printf with actual values, so the assembly output looks like an equivalent of:

    #include <stdio.h>
    int main() {
        printf("%d %d %d
    ", 3, 2, 515);
        return 0;
    }
    

    The value 515 can be obtained as other explained in other answers to this question. In essence it means that when gcc optimized the call it has chosen zeroes as the random value of a would-be uninitialized union.

Writing to one union member and reading from another usually does not make much sense, but sometimes it may be useful for programs compiled with strict aliasing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...