Document number: N2350
Submitter: Martin Sebor
Submission Date: March 18, 2019
Subject: Defining new types in offsetof

Summary

Among the questions raised by DR 496 and in Joseph Myers' paper on offsetof is whether conforming implementations are required to accept offsetof macro uses that define a new type as the type (first) argument. For example, does the standard intend to require conforming implementations to accept the following invocation of the macro? And if so, then what is the intended scope of the type definition?

      n = offsetof (struct S { int a; }, a);

No known implementation rejects this construct although Microsoft C issues:

      warning C4115: 'S': named type definition in parentheses

As Joseph notes in his paper, the type argument appears to meet the requirements of the standard, and in C (but not C++) types may be defined in casts and sizeof. However, requiring implementations to accept new types in offsetof would prevent traditional implementations of offsetof as a function-like macro because type definitions may include commas which are relied on by the preprocessor to separate macro arguments, and the traditional C preprocessor is not aware of the C grammar. For example, no known implementation accepts the following.

      n = offsetof (struct S { int a, b; }, a);

During past discussions of the defect the committee's consensus was that despite the absence of any statement to that effect, the standard does not intend to require implementatations to accept new types in offsetof. At the fall 2018 meeting the committee solicited words from the author to make this clear. This paper provides those words.


Suggested Change

To reflect existing implementation practice we propose to make the change below.

The macros are

	  NULL

which expands to an implementation-defined null pointer constant; and

	  offsetof(type, member-designator)

which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given

	  static type t;
then the expression &(t.member-designator) evaluates to an address constant. (If the specified type defines a new type or if the specified member is a bit-field, the behavior is undefined.)