1

Question: If we have two non-compatible structures or unions, but objects of both of the types have the same size of object representation would I get Undefined/Unspecified/Well-defined Behavior if I take object representation of some object of one of the types and "reinterpret" it as another type. (I do hope the wording is not weird).

My thoughts:

I mentioned the structure or union because N6.2.6.1(p6):

The value of a structure or union object is never a trap

Also I found that we can copy a value of an object into a char array 6.2.6.1(p4):

The value may be copied into an object of type unsigned char [n] (e.g., by memcpy); the resulting set of bytes is called the object representation of the value.

But the Standard does not specify that we can copy the object representation back. So I think it is UB to copy object representation back into an object of a type having representation of the same size (even if it's not a trap), but I'm not sure...

Example:

struct test1_t{
    int a;
    long b;
};

struct test2_t{
    int c;
    int d;
    int e;
    int f;
};


int main(){
      struct test1_t t1 = {.a = 100, .b = 2000};
      struct test2_t t2 = {.c = 1000, .d = 20000, .e = 300000, .f = 4000000};
      size_t size;
      if((size = sizeof(struct test1_t)) == sizeof(struct test2_t)){
          char repr[size];
          memcpy(&repr, &t2, size); // since value of structure or union
                                    // is never a trap why don't we treat
                                    // the representation as of some object
                                    // of type struct test_t1
          memcpy(&t1, &repr, size);
          printf("t1.a = %d\n", t1.a); //t1.a = 1000
          printf("t1.b = %d\n", t1.b); //t1.b = 300000
    }
}

The result can be explained with padding in struct test1_t after int a;.

Some Name
  • 8,555
  • 5
  • 27
  • 77
  • @EOF As mentioned in the referenced answer, we can use `memcpy` for type punning and in my case the behavior is well-defined since `t1` has declared type `struct test1_t` which is an effective type as well. – Some Name Mar 09 '19 at 13:23

1 Answers1

2

If we have two non-compatible structures or unions, but objects of both of the types have the same size of object representation would I get Undefined/Unspecified/Well-defined Behavior if I take object representation of some object of one of the types and "reinterpret" it as another type.

The question Can memcpy be used for type punning? and especially EOF's answer to it contain considerable relevant information and discussion, though they focus on different specifics. In particular,

  • the memcpy() itself is fine as long as the two types indeed have the same size (which appears unlikely to be the case in your example code), and
  • from there, it depends in part on whether the receiving object has a declared type.
    • if it does not, then subsequently accessing it via an lvalue of type different than the effective type of the source object produces UB.
    • if it does, as in your example, then accessing the structure itself is ok, for as you observed, structure types do not have trap representations.

HOWEVER, in the case of structures and unions, we also have to consider members. Their types may afford trap representations, and if they do, then the memcpy() may result in one or more members containing such a representation. Reading the value of a member that currently contains a trap representation produces UB.

Furthermore, even supposing that the two structure types in your example have the same size, relevant details of their layouts are unspecified. In particular, in your example code it would be surprising if both (1) the two structures have the same size and (2) the second printf call prints the result suggested by the code comment. (After correcting the format to match the data correctly; presently the printf has UB on account of the mismatch between format and variable.)

Overall, then, your example code is not strictly conforming. Aspects of its behavior are unspecified, and it is possible, but not certain, that it exhibits undefined behavior.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • _which appears unlikely to be the case in your example code_ But they do. I checked the `sizeof` output for both of them. It was equal to 16 on my machine. I guessed the padding took place for `struct test1_t::a`. – Some Name Mar 08 '19 at 17:28