Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using memcmp on array of int strictly conforming?

Is the following program a strictly conforming program in C? I am interested in c90 and c99 but c11 answers are also acceptable.

#include <stdio.h>
#include <string.h>

struct S { int array[2]; };

int main () {
    struct S a = { { 1, 2 } };
    struct S b;
    b = a;
    if (memcmp(b.array, a.array, sizeof(b.array)) == 0) {
        puts("ok");
    }
    return 0;
}

In comments to my answer in a different question, Eric Postpischil insists that the program output will change depending on the platform, primarily due to the possibility of uninitialized padding bits. I thought the struct assignment would overwrite all bits in b to be the same as in a. But, C99 does not seem to offer such a guarantee. From Section 6.5.16.1 p2:

In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.

What is meant by "converted" and "replaces" in the context of compound types?

Finally, consider the same program, except that the definitions of a and b are made global. Would that program be a strictly conforming program?

Edit: Just wanted to summarize some of the discussion material here, and not add my own answer, since I don't really have one of my own creation.

  • The program is not strictly conforming. Since the assignment is by value and not by representation, b.array may or may not contain bits set differently from a.array.
  • a doesn't need to be converted since it is the same type as b, but the replacement is by value, and done member by member.
  • Even if the definitions in a and b are made global, post assignment, b.array may or may not contain bits set differently from a.array. (There was little discussion about the padding bytes in b, but the posted question was not about structure comparison. c99 lacks a mention of how padding is initialized in static storage, but c11 explicitly states it is zero initialized.)
  • On a side note, there is agreement that the memcmp is well defined if b was initialized with memcpy from a.

My thanks to all involved in the discussion.

like image 795
jxh Avatar asked Aug 16 '12 19:08

jxh


1 Answers

In C99 §6.2.6

§6.2.6.1 General

1 The representations of all types are unspecified except as stated in this subclause.

[...]

4 [..] Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

6 When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.42)

42) Thus, for example, structure assignment need not copy any padding bits.

43) It is possible for objects x and y with the same effective type T to have the same value when they are accessed as objects of type T, but to have different values in other contexts. In particular, if == is defined for type T, then x == y does not imply that memcmp(&x, &y, sizeof (T)) == 0. Furthermore, x == y does not necessarily imply that x and y have the same value; other operations on values of type T may distinguish between them.

§6.2.6.2 Integer Types

[...]

2 For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits;[...]

[...]

5 The values of any padding bits are unspecified.[...]

In J.1 Unspecified Behavior

  • The value of padding bytes when storing values in structures or unions (6.2.6.1).

[...]

  • The values of any padding bits in integer representations (6.2.6.2).

Therefore there may be bits in the representation of a and b that differ while not affecting the value. This is the same conclusion as the other answer, but I thought that these quotes from the standard would be good additional context.


If you do a memcpy then the memcmp would always return 0 and the program would be strictly conforming. The memcpy duplicates the object representation of a into b.

like image 95
Geoff Reedy Avatar answered Nov 15 '22 05:11

Geoff Reedy