Consider the following C code fragment running on a 32-bit x86 machine:…
2019
Consider the following C code fragment running on a 32-bit x86 machine:
typedef struct {
union {
unsigned char a;
unsigned short b;
} U;
unsigned char c;
} S;
S B[10];
S *p = &B[4];
S *q = &B[5];
p->U.b = 0x1234;
/* structure S takes 32 bits */Assume the conventional 32-bit x86 ILP32 ABI: unsigned short is 2 bytes with 2-byte alignment, pointers and int are 32 bits, pointer-to-int conversion preserves the numerical address, and the displayed integer subtraction does not overflow.
If M is the value of q - p and N is the value of ((int)&(p->c)) - ((int)p), then (M, N) is:
- A.
(1, 1)
- B.
(3, 2)
- C.
(1, 2)
- D.
(4, 4)
Attempted by 148 students.
Show answer & explanation
Correct answer: C
Concept. Two independent C rules govern this item.
Pointer subtraction between two pointers into the same array yields the difference in element count, not bytes.
A member offset is determined by the layout, size, and alignment of preceding members; tail padding after the last member cannot shift an earlier member.
Application. Apply each rule to S on this 32-bit target where sizeof(S) = 4. The explicit ILP32 assumptions also make the two pointer-to-int conversions preserve their numerical addresses for this subtraction.
Compute
M = q - p. Herep = &B[4]andq = &B[5]point to consecutive elements of the same arrayB, so the element-count difference isM = 1(the byte gap ofsizeof(S)divided bysizeof(S), which is exactly the rule above).Lay out
S. The unionUholds anunsigned char(1 byte) and anunsigned short(2 bytes); a union's size is its largest member, sosizeof(U) = 2, occupying bytes 0 and 1 at offset 0.Place
c. The next memberunsigned char cfollowsUat the next free byte, socsits at byte offset 2.Compute
N = ((int)&(p->c)) - ((int)p). Under the stated address-preserving ILP32 assumptions, subtracting the converted numerical addresses yields the byte offset ofcwithinS, which isN = 2.
Cross-check. The struct is rounded up to sizeof(S) = 4 for alignment; that 1 byte of tail padding sits AFTER c (byte 3). Pointer subtraction counts elements, so the padded sizeof(S) is what makes the stride exactly one element and never alters c's offset of 2. Writing p->U.b = 0x1234 only stores bytes into the union and, with endianness, never moves a member offset. Both rules therefore give (M, N) = (1, 2).
Note. The line S B[10]; is an array declaration, not an assignment, so the absence of = is correct.
A video solution is available for this question — log in and enroll to watch it.