6.5.0 General
An expression is a sequence of operators and operands that specifies a computation of a value, that designates an object, that produces effects, or that performs some combination of these.
6.5.0.1 Evaluation order
Subexpressions are evaluated from left to right, unless the syntax of the construct specifies a different control dependency.
The constructs that specify a different control dependency are:
- the logical AND operator, clause 6.5.13,
- the logical OR operator, clause 6.5.14,
- the conditional operator, clause 6.5.15,
- the controlling expressions and bodies of statements, clause 6.8.
Everything else evaluates left to right, including:
- both operands of every binary arithmetic, bitwise, relational, and equality operator,
- the called expression and then the arguments of a function call, in written order,
- the destination and then the source of an assignment,
- the operands of the comma operator,
- the elements of an initializer list, in written order,
- the array expression and then the subscript expression of a subscript operator.
Effects.
A side effect is a modification of an object, a modification of a file, or a call to a function that does either. An effect of an evaluation takes place before the next evaluation in the order begins.
Consequently, every expression has a determined result:
int i = 1;
i = i++; /* i is 1: the increment happens, then the old value is stored */
a[i++] = i; /* the index is the old i; the stored value is the new i */
f(g(), h()); /* g() runs, then h(), then f */
Diagnostics. An implementation should diagnose an expression that modifies an object more than once, or that both modifies and independently reads an object, within one full expression. The behavior is defined, and the code is still difficult to read. A defined answer removes the metaphysics, not the poor style. See syntax.md section 27.
Difference: ISO C99 leaves the order of evaluation of subexpressions and of function arguments unspecified, and treats certain combinations of side effects as undefined. Ocean Edition I has no unspecified evaluation order and no sequence points. See behavior.md sections 65 and 104, and annex-e-evaluation-order.md.
6.5.0.2 Precedence and grouping
Operator precedence and associativity determine which operator consumes which value. Evaluation order determines when those values are produced. The two are independent.
a() + b() * c()
groups as a() + (b() * c()), and evaluates the calls in the order a(), b(), c().
Precedence and associativity are unchanged from C and are given by the grammar in annex-a-grammar.md.
6.5.0.3 Lvalues, arrays, and function designators
An lvalue designates an object. Where a value is required, an lvalue undergoes lvalue conversion under clause 6.3.2.1.
An expression of array type has array type. An expression of function type has function type. Neither is converted by context. See clause 6.3.2.1.
6.5.0.4 Aliasing and access to object representation
Ordinary pointers may alias.
An implementation shall not conclude that two pointers designate distinct storage merely because their referenced types differ. There is no type-based aliasing rule and no effective type.
Stronger alias facts come from one of the following:
- a proof the implementation performed,
- a
restrictcontract the programmer wrote, under clause 6.7.3.3, - a property of the selected target.
See syntax.md section 36 and behavior.md section 77.
Access through character types.
The object representation of any object may be read and written through a pointer to char, signed char, or unsigned char. Such an access is defined for every byte of the object, including padding bytes.
Access through a different member of a union.
Writing one member of a union and then reading another reinterprets the stored object representation through the type of the member read. This is defined. A union does not maintain a hidden active member. See clause 6.5.2.3 and behavior.md section 22.
Access through an unrelated type.
Reading storage through a pointer to a type whose representation the storage does not currently hold produces the value obtained by interpreting those bytes as the accessed type. If the bytes do not form a valid representation of that type, and the type is not an integer type, the result is unsafe memory behavior. Integer types have no invalid representations, so integer reinterpretation always yields a value. See clause 6.2.6.2.
6.5.0.5 Truth of scalar values
A scalar value used as a condition, or as an operand of a logical operator, is interpreted as follows:
| Value | Truth |
|---|---|
| integer zero | false |
| floating zero, positive or negative | false |
| null pointer | false |
| a null constant | false |
| any other scalar value | true |
A NaN is true, because it is not numerical zero.
No separate Boolean-only condition syntax exists. A scalar expression is a condition. See behavior.md sections 14 and 72.
6.5.0.6 Traps in expressions
Some operations cannot produce a valid result. Those operations cause a defined trap rather than undefined behavior. Within an expression, the first trap in evaluation order is the one that occurs, and evaluations sequenced before it have completed.
The complete list is in annex-d-defined-traps-and-unsafe-operations.md. The operations appearing in this clause are division by zero, remainder by zero, an unrepresentable signed division result, an out-of-range shift count, an out-of-range floating-to-integer conversion, an unrepresentable pointer computation, and a detected incompatible call.
6.5.1 Primary Expressions
primary-expression:
identifier
qualified-identifier
constant
string-literal
( expression )
An identifier that has been declared as designating an object is an lvalue of that object's type. An identifier declared as a function is a function designator of that function's type. An identifier declared as an enumeration constant has the value and the enumerated type of that constant.
An identifier that has not been declared is a constraint violation. There is no implicit declaration of any kind.
A parenthesized expression has the type, value, and lvalue status of the expression it encloses.
ISO C99 mapping: 6.5.1.
6.5.1.1 Qualified identifiers
qualified-identifier:
:: identifier
namespace-qualification :: identifier
namespace-qualification:
namespace-name
namespace-qualification :: namespace-name
A qualified identifier names an entity in a particular namespace.
Constraints.
Each namespace-name shall name a namespace that is visible at the point of use. The identifier shall name an entity declared in the namespace the qualification designates.
A qualified identifier shall not name an entity with no linkage, since such an entity is not a member of any namespace.
Semantics.
::identifier names the entity in the global namespace, ignoring any namespace enclosing the point of use.
a::identifier names the entity in namespace a. a::b::identifier names the entity in namespace b nested within a.
A qualified identifier has the type, the value category, and the lvalue status the declaration gives it. Qualification affects which declaration is found and nothing else.
namespace net
{
int open(const char *host);
}
int open(const char *path);
void f(void)
{
net::open(&host[0]); /* the one in net */
::open(&path[0]); /* the one in the global namespace */
}
6.5.1.2 What may be qualified
Qualification reaches a member in the ordinary identifier and tag name spaces of clause 6.2.3, and the syntax differs only in where the qualification is written.
| Kind | Written |
|---|---|
| object or function | net::open |
| enumeration constant | net::STATE_IDLE |
| typedef name | net::index_t |
| structure, union, or enumeration tag | struct net::Header, enum net::State |
A tag is qualified after the keyword, because the qualification names the tag rather than the keyword.
A label shall not be qualified. Labels have function scope under clause 6.2.1 and are not members of any namespace.
A structure or union member shall not be qualified. It is reached through the . or -> operator, which already determines which type's member name space applies.
net::Header header; /* invalid: Header is a tag */
struct net::Header header; /* correct */
header.length = 4; /* correct */
header.net::length = 4; /* invalid: members are not qualified */
6.5.1.3 Unqualified lookup
An unqualified identifier is looked up in the following order, and the first declaration found is the one used:
- the block scopes enclosing the point of use, from innermost outward,
- the innermost namespace enclosing the point of use, then each enclosing namespace in turn, outward,
- the global namespace.
Lookup stops at the first namespace in which the identifier is declared. It does not continue outward to collect further declarations, and it does not merge declarations found at different levels.
Reopening does not create a second scope. Every definition of a namespace, and every source file governed by a #namespace directive naming it, contributes to one namespace for the purpose of this clause. A member declared in one definition is found by lookup in another:
namespace net
{
int open(const char *host);
}
namespace net
{
int reopen(const char *host)
{
return open(host); /* found: one namespace, two definitions */
}
}
Within one namespace, two declarations of the same identifier declare the same entity when they are compatible under clause 6.9.5, and are a constraint violation otherwise. Lookup therefore never has to choose between them.
int reset(void);
namespace net
{
int reset(void);
void restart(void)
{
reset(); /* net::reset, found at step 2 */
::reset(); /* the global one, named explicitly */
}
}
Constraints.
An unqualified identifier that no step finds is a constraint violation, as clause 6.5.1 requires for any undeclared identifier.
Note. Lookup can find a name in an enclosing namespace, so an entity in the global namespace remains reachable without qualification from inside a namespace. This is what allows the standard library and every ordinary C declaration to be used inside a namespace without change:
namespace net
{
int open(const char *host)
{
return socket(AF_INET, SOCK_STREAM, 0); /* found in the global namespace */
}
}
Note. A declaration in an inner namespace hides one of the same name in an enclosing namespace, the same way a block-scope declaration hides a file-scope one. An implementation should diagnose a hiding declaration that is likely to be accidental.
ISO C99 mapping: new.
6.5.2 Postfix Operators
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-list-opt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
( type-name ) { initializer-list }
( type-name ) { initializer-list , }
6.5.2.1 Array subscripting
Constraints.
In E1[E2], one operand shall have array type or pointer-to-object type, and the other shall have integer type. The result has the element type or the referenced type.
Semantics.
E1 is evaluated, then E2, then the subscript is applied.
If the left operand has array type, a[i] designates the element of a at index i, counted from zero. No pointer is formed and no conversion occurs.
If the left operand has pointer type, p[i] is identical to *(p + i) and follows clause 6.5.6.
Subscripting an array with an index outside the range 0 through N - 1 is unsafe memory behavior. When the index and the extent are both known at translation time, an implementation shall diagnose the access and shall not translate the program. See clause 4.3.
int values[16];
values[0] = 1; /* fine */
values[16] = 1; /* constraint violation, diagnosed */
int *p = &values[0];
p[16] = 1; /* unsafe memory behavior, not diagnosable in general */
ISO C99 mapping: 6.5.2.1.
6.5.2.2 Function calls
Constraints.
The expression preceding the parentheses shall have function type, or shall have type pointer to function.
The number of arguments shall equal the number of parameters, unless the function type ends with an ellipsis, in which case the number of arguments shall be at least the number of named parameters.
Each argument shall have a type assignable to the corresponding parameter type under clause 6.5.16.1.
Because every function declaration is a prototype, these constraints are always checkable. There is no category of call whose argument types are unknown to the language. See clause 6.7.5.3.
Semantics.
The called expression is evaluated first. Then the arguments are evaluated from left to right. Then the call is performed.
f(a(), b(), c());
evaluates in the order:
f
a()
b()
c()
call
A function designator may be called directly, and a pointer to function may be called with the same syntax:
compare(1, 2); /* compare is a function designator */
fn(1, 2); /* fn is a pointer to function */
Neither form requires the programmer to insert or remove a * or an &.
Arguments matched against declared parameters are converted as if by assignment. Arguments in the variadic tail undergo the default argument promotions of clause 6.3.1.8.
Recursion is permitted, including indirect recursion.
The value of the call is the returned value, converted to the return type. If the function returns void, the call produces no value.
Call type safety.
A call shall agree with the function's declared type. Calling a function through a pointer whose type is not compatible with the function's type is invalid.
- If the incompatibility is statically known, the implementation shall diagnose it and shall not translate the program.
- If the incompatibility arises at execution time through a cast, execution shall fail in a defined manner wherever the implementation can detect it, and is otherwise unsafe memory behavior.
An implementation shall not treat a calling-convention mismatch as an optimization opportunity or as a fact about the program. See behavior.md section 39.
ISO C99 mapping: 6.5.2.2.
6.5.2.3 Structure and union members
Constraints.
The left operand of . shall have structure or union type, and the identifier shall name a member of that type.
The left operand of -> shall have type pointer to structure or pointer to union, and the identifier shall name a member of the pointed-to type.
Semantics.
E1.member designates the named member of the structure or union E1. It is an lvalue if E1 is an lvalue, and it carries the qualifiers of E1 combined with those of the member.
E1->member is identical to (*E1).member.
Reading a union member other than the one last written reinterprets the stored representation:
union Value
{
float f;
uint32_t u;
};
union Value value;
value.f = 1.0f;
uint32_t bits = value.u; /* defined: 0x3F800000 on an IEC 60559 target */
ISO C99 mapping: 6.5.2.3.
6.5.2.4 Postfix increment and decrement
Constraints.
The operand shall be a modifiable lvalue of real arithmetic type or of pointer type.
Semantics.
The result is the value of the operand before the modification. After the value is taken, 1 is added to or subtracted from the object.
Overflow follows the ordinary integer rules of clause 6.5.6, which means it wraps rather than trapping. Pointer increment follows clause 6.5.6.
ISO C99 mapping: 6.5.2.4.
6.5.2.5 Compound literals
Constraints.
The type name shall specify a complete object type, and may specify an array type with a known element count or an array type whose count the initializer determines. The initializer list shall satisfy clause 6.7.9.
This production is distinct from the cast of clause 6.5.4, which shall not specify an array type.
Semantics.
A compound literal creates an unnamed object of the specified type, initialized by the list. The result is an lvalue.
At block scope the object has automatic storage duration associated with the enclosing block. At file scope it has static storage duration.
struct Point origin = (struct Point){
.x = 0,
.y = 0,
};
draw(&(struct Point){
.x = 10,
.y = 20,
});
Members not specified in the list are zero-initialized, under clause 6.7.9.2.
A compound literal of array type is an array object. It does not convert to a pointer, so the address of its first element is written explicitly:
sum(&(int[4]){ 1, 2, 3, 4 }[0], 4);
ISO C99 mapping: 6.5.2.5.
6.5.3 Unary Operators
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
unary-operator:
& * + - ~ !
6.5.3.1 Prefix increment and decrement
The operand shall be a modifiable lvalue of real arithmetic type or of pointer type. ++E is equivalent to E += 1, and --E is equivalent to E -= 1. The result is the value after the modification, and it is not an lvalue.
ISO C99 mapping: 6.5.3.1.
6.5.3.2 Address and indirection operators
The address operator.
The operand of unary & shall be an lvalue, a function designator, or an expression of the form *E or E1[E2].
&objectproduces a pointer to the object.&functionproduces a pointer to the function. This is the only way a function pointer is produced, since function designators do not convert. See clause 6.3.2.1.&arrayproduces a pointer to the whole array, of type pointer to array.&array[0]produces a pointer to the first element, of type pointer to the element type.
The last two are different types and are not interchangeable:
int values[16];
int (*whole)[16] = &values;
int *first = &values[0];
The operand shall not be a bitfield member, and shall not be an object declared with a storage class that has no address. Taking the address of an object with automatic storage duration is permitted; keeping that pointer after the object's lifetime ends is unsafe.
The indirection operator.
The operand of unary * shall have pointer type. If the operand points to an object, the result is an lvalue designating that object. If the operand points to a function, the result is a function designator.
Dereferencing a null pointer, a pointer whose target lifetime has ended, or a pointer that does not designate a valid object is unsafe memory behavior. An implementation shall diagnose a provable null dereference at translation time.
ISO C99 mapping: 6.5.3.2.
6.5.3.3 Unary arithmetic operators
Unary plus.
The operand shall have arithmetic type. The result is the promoted value of the operand.
Unary minus.
The operand shall have arithmetic type. The result is the negative of the promoted value.
For an integer operand, negation is finite-width two's-complement negation, computed as subtraction from zero. Negating the minimum representable value of a signed type yields that same minimum value. It does not trap and it is not undefined.
int32_t x = INT32_MIN;
int32_t y = -x; /* y == INT32_MIN */
Bitwise complement.
The operand shall have integer type. The result is the promoted value with each bit of its representation inverted. Because signed integers are two's complement with no padding bits, the result is determined for every operand.
Logical negation.
The operand shall have scalar type. The result is 1 if the operand compares equal to zero under clause 6.5.0.5, and 0 otherwise. The result has type int.
ISO C99 mapping: 6.5.3.3.
6.5.3.4 The sizeof operator
Constraints.
The operand shall not have function type, shall not have an incomplete type, and shall not be a bitfield member.
Semantics.
sizeof yields the size in bytes of its operand's type. The result has type size_t and is an integer constant expression.
The operand is not evaluated. Because there are no variable-length arrays, no operand of sizeof can have a size that depends on execution, so sizeof is always a translation-time value.
Because arrays do not convert to pointers:
int values[16];
sizeof(values) /* 16 * sizeof(int) */
sizeof(&values[0]) /* size of a pointer */
sizeof(int [16]) /* 16 * sizeof(int) */
sizeof(char), sizeof(signed char), and sizeof(unsigned char) are 1.
sizeof applied to a structure includes its padding. sizeof applied to a structure with a flexible array member yields a size to which the flexible member contributes nothing. See clause 6.7.2.2.
ISO C99 mapping: 6.5.3.4.
6.5.4 Cast Operators
cast-expression:
unary-expression
( type-name ) cast-expression
Constraints.
The type name shall specify a scalar type or void. The operand shall have scalar type, unless the target type is void.
A cast shall not specify an array type or a function type.
A compound literal is not a cast. The two use the same ( type-name ) spelling and are different productions, distinguished by what follows the closing parenthesis. A compound literal is followed by a brace-enclosed initializer list, may specify an array type, and produces an lvalue designating an object. A cast is followed by an expression, may not specify an array type, and produces a value.
(int [4]){ 1, 2, 3, 4 } /* compound literal: an array object */
(int [4])x /* invalid: a cast to an array type */
See clause 6.5.2.5.
Conversions between a pointer type and a floating type are not permitted.
Semantics.
A cast converts the value of the operand to the named type, following clause 6.3. Casting a value to its own type is permitted and produces the value.
Casts remain powerful and remain the programmer's responsibility:
void *p = allocate();
int *q = (int *)p;
The programmer is responsible for the storage being suitable. See clause 6.2.6.5.
What a cast does not do.
- Casting away
constdoes not make a subsequent modification of aconstobject valid. See clause 6.7.3.1. - Casting a function pointer does not make a call through it compatible. See clause 6.5.2.2.
- Casting a pointer does not change the alignment of the storage it designates.
- Casting does not suppress a defined trap.
An implementation should diagnose a cast that has no effect.
ISO C99 mapping: 6.5.4.
6.5.5 Multiplicative Operators
Constraints.
Each operand of * and / shall have arithmetic type. Each operand of % shall have integer type.
Semantics.
The usual arithmetic conversions of clause 6.3.1.6 are applied.
Multiplication yields the product. Integer multiplication is finite-width two's-complement multiplication, so a result outside the range of the type wraps rather than trapping.
Division yields the quotient with any fractional part discarded, truncating toward zero:
7 / 3 /* 2 */
-7 / 3 /* -2 */
7 / -3 /* -2 */
Remainder yields the remainder, satisfying:
a == (a / b) * b + (a % b)
for every pair of operands for which the division yields a value. The sign of the remainder follows the sign of the dividend:
7 % 3 /* 1 */
-7 % 3 /* -1 */
Traps.
a / 0anda % 0cause a defined trap.- Signed division where the dividend is the minimum representable value of its type and the divisor is
-1causes a defined trap, because the exact quotient is2^(N-1)and has no representation in the type.
Remainder of the minimum value by negative one.
Where the dividend is the minimum representable value and the divisor is -1, the remainder operator yields zero. It does not trap.
int32_t a = INT32_MIN;
a / -1 /* traps */
a % -1 /* 0 */
The exact mathematical remainder is zero, and zero is representable, so there is a correct answer and this edition gives it. The identity above does not apply to this pair, because the division has no value to substitute into it.
Implementation note. On a target whose divide instruction computes the quotient and the remainder together and faults on this pair, an implementation shall test for it. The test is the one the division case already requires, so a remainder that returns zero costs a branch that was going to be there regardless.
Difference: ISO C99 makes both cases undefined. Ocean Edition I traps on the division and defines the remainder.
Design note: which operations wrap and which trap.
The edition applies one principle, and the two behaviors are not arbitrary.
An operation whose finite-width behavior is a natural modular operation wraps. Addition, subtraction, multiplication, left shift, and unary negation are defined on the whole of the two's-complement value set, so every operand pair produces a representable result and there is nothing to refuse.
An operation defined by an exact mathematical result traps only when that exact result has no representation. Division is the case in point: the quotient of the minimum value by -1 is one greater than the maximum, and no answer exists. Wrapping it would return the minimum value, which is not the quotient in any interpretation.
Applying the same test to remainder gives zero rather than a trap, which is why this clause defines it. A trap is a statement that no correct answer exists. Where one exists, the language produces it.
Floating division by zero has an answer under IEC 60559, so it does not trap either. It produces an infinity or a NaN according to the operands. See annex-f-floating-point.md clause F.3.
See behavior.md sections 58 and 59.
ISO C99 mapping: 6.5.5.
6.5.6 Additive Operators
Constraints.
For +, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.
For -, either both operands shall have arithmetic type, or the left operand shall be a pointer to a complete object type and the right operand shall have integer type, or both operands shall be pointers to compatible complete object types after removing qualifiers.
An array operand does not satisfy the pointer requirement. Write &a[0].
Arithmetic semantics.
The usual arithmetic conversions are applied. Integer addition and subtraction are finite-width two's-complement operations. A result outside the range of the type wraps:
int32_t x = INT32_MAX;
int32_t y = x + 1; /* y == INT32_MIN */
Difference: ISO C99 makes signed overflow undefined and unsigned overflow modular. Ocean Edition I gives both defined finite-width behavior, and an implementation shall not derive facts from the assumption that overflow does not occur. See clause 4.7, syntax.md section 31, and behavior.md section 54.
Pointer arithmetic.
For a pointer p of type T * and an integer n:
p + nandn + pyield the addresspadvanced bynobjects of typeT,p - nyields the addresspmoved back bynobjects of typeT.
The computation is address arithmetic scaled by sizeof(T). If the mathematical result cannot be represented in the target pointer model, the operation causes a defined trap.
Forming a pointer that does not designate a valid object is permitted. Dereferencing such a pointer is unsafe memory behavior. This separation is deliberate: computing an address is arithmetic, and using it is an access. See behavior.md section 33.
Pointer subtraction.
For two pointers p and q to compatible complete object types, p - q yields the number of elements between them, computed as the difference of their addresses divided by the size of the pointed-to type. The result has type ptrdiff_t.
- If the byte difference is not an exact multiple of the element size, the operation causes a defined trap.
- If the result is not representable in
ptrdiff_t, the operation causes a defined trap.
The operands need not point into the same array object. On a flat address space the difference of two addresses is meaningful, and this edition says so.
Difference: ISO C99 restricts pointer arithmetic and pointer subtraction to a single array object, one past its end included, and makes everything else undefined.
ISO C99 mapping: 6.5.6.
6.5.7 Bitwise Shift Operators
Constraints.
Each operand shall have integer type.
Semantics.
The integer promotions are applied to each operand separately. The type of the result is the promoted type of the left operand. The right operand does not participate in the usual arithmetic conversions.
Shift count.
Let W be the width in bits of the promoted left operand. The shift count shall satisfy:
0 <= count < W
A count outside this range, including a negative count, causes a defined trap. When the count is a constant, the implementation shall diagnose it at translation time.
Left shift.
E1 << E2 shifts the bit representation of E1 left by E2 positions. Vacated low-order bits are filled with zeros. Bits shifted beyond the width are discarded. The resulting bit pattern is interpreted according to the result type.
A signed left shift does not become invalid merely because the mathematical result exceeds the positive range:
int32_t x = 1;
int32_t y = x << 31; /* INT32_MIN, defined */
Right shift.
E1 >> E2 shifts the bit representation of E1 right by E2 positions.
- If the result type is unsigned, vacated high-order bits are filled with zeros.
- If the result type is signed, the shift is arithmetic and vacated high-order bits are filled with copies of the sign bit.
Therefore the result is the same on every implementation:
int32_t x = -8;
int32_t y = x >> 1; /* -4 */
Difference: ISO C99 makes an out-of-range shift count undefined, makes signed left shift overflow undefined, and makes signed right shift implementation-defined. Ocean Edition I defines the first as a trap and defines the other two. See behavior.md sections 60 through 62.
ISO C99 mapping: 6.5.7.
6.5.8 Relational Operators
Constraints.
Either both operands shall have real arithmetic type, or both shall be pointers to compatible object types after removing qualifiers.
Arithmetic comparison.
Arithmetic operands are compared by mathematical value under clause 6.3.1.7, not by converted representation. Therefore -1 < 1u is true.
Pointer comparison.
Relational comparison of two object pointers compares their addresses within the implementation's address space:
a < b /* true when the address in a is lower than the address in b */
The operands need not point into the same array object. This matches the ordinary systems-programming model of ordered machine addresses. See behavior.md section 32.
Comparing a null pointer relationally with a non-null pointer compares the null representation as an address, which on supported targets is zero and therefore orders below every valid object address.
Floating comparison.
If either operand is a NaN, every relational operator yields 0.
Result.
The result has type int and the value 1 or 0.
Difference: ISO C99 makes relational comparison of pointers into different objects undefined, and converts mixed signed and unsigned operands before comparing.
ISO C99 mapping: 6.5.8.
6.5.9 Equality Operators
Constraints.
One of the following shall hold:
- both operands have arithmetic type,
- both operands are pointers to compatible types after removing qualifiers,
- one operand is a pointer to an object type and the other is a pointer to
void, - one operand is a pointer and the other is a null constant,
- both operands have type
null_t, - both operands are pointers to compatible function types.
Semantics.
Arithmetic operands are compared by mathematical value under clause 6.3.1.7. Therefore -1 == 0xFFFFFFFFu is false.
Two pointers compare equal when both are null pointers, or when both designate the same address and belong to the same pointer category. Object pointers and function pointers belong to different categories and never compare equal to each other without an explicit cast.
A null pointer compares equal only to another null pointer, after the ordinary conversions. Comparing a pointer with a null constant converts the constant to the pointer's type first, so p == null tests whether p is a null pointer.
If either floating operand is a NaN, == yields 0 and != yields 1.
The result has type int and the value 1 or 0.
ISO C99 mapping: 6.5.9.
6.5.10 Bitwise AND Operator
Each operand shall have integer type. The usual arithmetic conversions are applied. The result is the bitwise AND of the operand representations.
Because signed integers are two's complement with no padding bits, the result is determined for every pair of operands.
ISO C99 mapping: 6.5.10.
6.5.11 Bitwise Exclusive OR Operator
Each operand shall have integer type. The usual arithmetic conversions are applied. The result is the bitwise exclusive OR of the operand representations.
ISO C99 mapping: 6.5.11.
6.5.12 Bitwise Inclusive OR Operator
Each operand shall have integer type. The usual arithmetic conversions are applied. The result is the bitwise inclusive OR of the operand representations.
ISO C99 mapping: 6.5.12.
6.5.13 Logical AND Operator
Each operand shall have scalar type.
The left operand is evaluated. If it compares equal to zero, the result is 0 and the right operand is not evaluated. Otherwise the right operand is evaluated, and the result is 1 if it does not compare equal to zero, and 0 otherwise.
The result has type int.
ISO C99 mapping: 6.5.13.
6.5.14 Logical OR Operator
Each operand shall have scalar type.
The left operand is evaluated. If it does not compare equal to zero, the result is 1 and the right operand is not evaluated. Otherwise the right operand is evaluated, and the result is 1 if it does not compare equal to zero, and 0 otherwise.
The result has type int.
ISO C99 mapping: 6.5.14.
6.5.15 Conditional Operator
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
Constraints.
The first operand shall have scalar type. One of the following shall hold for the second and third operands:
- both have arithmetic type,
- both have the same structure or union type,
- both have
voidtype, - both are pointers to compatible types after removing qualifiers,
- one is a pointer and the other is a null constant,
- one is a pointer to an object type and the other is a pointer to
void, - both have the same array type, in which case the result has that array type and is an lvalue only if both operands are lvalues designating the same object.
Semantics.
The first operand is evaluated. Exactly one of the second and third operands is evaluated, according to whether the first compared equal to zero.
The result type is determined by the operand types: the usual arithmetic conversions for arithmetic operands, the composite type for pointer operands, and a pointer to the appropriately qualified void where one operand is void *.
The result is not an lvalue unless both operands are lvalues designating the same object.
ISO C99 mapping: 6.5.15.
6.5.16 Assignment Operators
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator:
= *= /= %= += -= <<= >>= &= ^= |=
Constraints.
The left operand shall be a modifiable lvalue.
Semantics common to all forms.
The left operand is evaluated first, to determine which object is designated. Then the right operand is evaluated. Then the value is converted and stored.
An assignment expression has the value of the left operand after the store, with its type after lvalue conversion. It is not an lvalue.
Assignment as an expression is retained, because it is idiomatic and coherent:
int c;
while ((c = getchar()) != EOF)
{
process(c);
}
See syntax.md section 49.
6.5.16.1 Simple assignment
The value of the right operand is converted to the type of the left operand and stored.
One of the following shall hold:
- the left operand has an arithmetic type and the right operand has an arithmetic type,
- the left and right operands have compatible structure or union types,
- both operands are pointers to compatible types, and the left operand's referenced type has at least the qualifiers of the right operand's referenced type,
- one operand is a pointer to an object type and the other is a pointer to
void, with the same qualifier requirement, - the left operand is a pointer and the right operand is a null constant,
- the left operand has type
booland the right operand is a pointer or a null constant, - both operands have type
null_t, - the right operand is a string literal and the left operand is a compatible character pointer as clause 6.3.2.4 defines that term.
Array assignment is not permitted, because an array lvalue is not modifiable. Copy an array by copying a structure that contains it, by copying element by element, or by a library copy function.
Structure and union assignment copies the complete object representation, including padding, under clause 6.2.6.1:
struct Point a;
struct Point b = { .x = 1, .y = 2 };
a = b; /* a is representation-equivalent to b */
If the left and right operands designate overlapping storage of the same type, the result is as though the source were read completely before the destination was written.
6.5.16.2 Compound assignment
E1 op= E2 behaves as E1 = E1 op (E2), except that the lvalue E1 is evaluated only once.
The operation follows the rules of the corresponding binary operator, including its conversions, its overflow behavior, and its traps. The result is converted to the type of E1 and stored, which may narrow the value under clause 6.3.1.3.
uint8_t b = 200;
b += 100; /* b == 44, by defined narrowing */
An implementation should diagnose a compound assignment whose narrowing store loses information, where that is statically evident.
ISO C99 mapping: 6.5.16.
6.5.17 Comma Operator
expression:
assignment-expression
expression , assignment-expression
The left operand is evaluated, its value is discarded, and then the right operand is evaluated. The result has the type and value of the right operand and is not an lvalue.
A comma separating function arguments or initializer list elements is not the comma operator; it is punctuation. In those positions, a comma operator shall be written inside parentheses.
ISO C99 mapping: 6.5.17.