Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using an union in place of a cast well defined?

I had a discussion this morning with a colleague regarding the correctness of a "coding trick" to detect endianness.

The trick was:

bool is_big_endian()
{
  union
  {
    int i;
    char c[sizeof(int)];
  } foo;


  foo.i = 1;
  return (foo.c[0] == 1);
}

To me, it seems that this usage of an union is incorrect because setting one member of the union and reading another is not well-defined. But I have to admit that this is just a feeling and I lack actual proofs to strengthen my point.

Is this trick correct ? Who is right here ?

like image 327
ereOn Avatar asked May 26 '11 08:05

ereOn


People also ask

Why do we use unions?

A union is a special data type available in C that allows to store different data types in the same memory location. You can define a union with many members, but only one member can contain a value at any given time. Unions provide an efficient way of using the same memory location for multiple-purpose.

Why do we need unions in C?

Like Structures, union is a user defined data type. In union, all members share the same memory location. For example in the following C program, both x and y share the same location. If we change x, we can see the changes being reflected in y.

What is union explain with example?

A union is a user-defined type similar to structs in C except for one key difference. Structures allocate enough space to store all their members, whereas unions can only hold one member value at a time.


2 Answers

Your code is not portable. It might work on some compilers or it might not.

You are right about the behaviour being undefined when you try to access the inactive member of the union [as it is in the case of the code given]

$9.5/1

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time.

So foo.c[0] == 1 is incorrect because c is not active at that moment. Feel free to correct me if you think I am wrong.

like image 197
Prasoon Saurav Avatar answered Oct 01 '22 17:10

Prasoon Saurav


Don't do this, better use something like the following:

#include <arpa/inet.h>
//#include <winsock2.h> // <-- for Windows use this instead

#include <stdint.h>

bool is_big_endian() {
  uint32_t i = 1;
  return i == htonl(i);
}

Explanation:

The htonl function converts a u_long from host to TCP/IP network byte order (which is big-endian).


References:

  • http://linux.die.net/man/3/htonl
  • http://msdn.microsoft.com/de-de/library/ms738556%28v=vs.85%29.aspx
like image 37
moooeeeep Avatar answered Oct 01 '22 17:10

moooeeeep