C, Ocean Edition I

6.5 Expressions

Clause
6.5
ISO C99 mapping
6.5
Status
Normative

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:

Everything else evaluates left to right, including:

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:

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:

  1. the block scopes enclosing the point of use, from innermost outward,
  2. the innermost namespace enclosing the point of use, then each enclosing namespace in turn, outward,
  3. 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.

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].

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.

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.

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:

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.

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.

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:

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:

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:

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.