Issue 1122: Constraints on string literals and character constants

Authors: Jay Ghiron
Date: 2026-10-14
Submitted against: C23
Status: Open
Cross-references: 0265, 1113

For the following questions assume that the following macro is always defined:

#define IGNORE(...)

Question 1

The same considerations apply to each element of the sequence in a string literal as if it were in an integer character constant (for a character or UTF-8 string literal) or a wide character constant (for a wide string literal), except that the single-quote ' is representable either by itself or by the escape sequence \', but the double-quote " shall be represented by the escape sequence \".

(C23 6.4.6 "String literals" paragraph 4.)

This appears to apply the constraints of octal escape sequences and hexadecimal escape sequences as specified earlier for character constants to string literals. Does this apply the constraints before string literal concatenation or after string literal concatenation? For example:

const typeof(u' ')a[]=u"""\400";

If CHAR_BIT is eight, it is unclear whether or not this declaration has a constraint violation.

Question 2

Do the constraints on octal escape sequences and hexadecimal escape sequences apply to preprocessing tokens which are never converted to tokens? For example:

IGNORE('\400')
IGNORE("\400")
#if 0
'\400'
"\400"
#endif

Must these invalid octal escape sequences be rejected if CHAR_BIT is eight? If question one is resolved as applying the constraints after string literal concatenation, then the answer for string literals is obvious.

Question 3

Do the constraints on universal character names apply to string literal preprocessing tokens and character constant preprocessing tokens which in either case are never converted to tokens? For example:

IGNORE('\uD800')
IGNORE("\uD800")
#if 0
'\uD800'
"\uD800"
#endif

GCC, Clang, MSVC, and EDG all accept this and the example in question two. Inside of skipped groups there is disagreement about whether the constraints apply to identifiers and preprocessing numbers: GCC and Clang reject, while MSVC and EDG accept.

Question 4

For the purposes of this token conversion and evaluation, all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>. This includes interpreting character constants, which can involve converting escape sequences into execution character set members.

(C23 6.10.2 "Conditional inclusion" paragraph 13.)

Does this mean that inside of conditional expression inclusion preprocessing directives the constraints on character constants are based on uintmax_t? For example:

#if'\400'
#endif

Is this valid when CHAR_BIT is eight? If the range of char is interpreted as being affected because both signed char and unsigned char are affected, then it appears that this could also affect the resulting value:

#if'\377'==-1
#error
#endif

Is this valid for any value of CHAR_MAX? GCC, Clang, MSVC, and EDG all reject both of the previous examples in this question. It should also be considered if character constants that contain a single character or a single escape sequence which in either case is in the basic character set (source or execution depending upon how issue 1113 is resolved) can have a value not normally possible:

#include<limits.h>
#if'a'>CHAR_MAX
#error
#endif

Can this be invalid? See also DR 265.