Pergunta

I have code like this:

$ cat test.c 
#include <stdio.h>
typedef struct
{
    const int x;
} SX;

static SX mksx(void)
{
    return (SX) { .x = 10 };
}

void fn(void)
{
    SX sx;
    while((sx = mksx()).x != 20)
    {
        printf("stupid code!");
    }
}

And 2 opinions about its correctness:

$ for i in gcc clang; do echo "$i SAYS:"; $i -c -std=c99 -pedantic -Werror test.c; done
gcc SAYS:
test.c: In function ‘fn’:
test.c:15:2: error: assignment of read-only variable ‘sx’
  while((sx = mksx()).x != 20)
  ^
clang SAYS:

Which compiler is right?

Foi útil?

Solução

The C99 standard says in 6.5.16:2:

An assignment operator shall have a modifiable lvalue as its left operand.

and in 6.3.2.1:1:

A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.

So GCC is right to warn.

In addition, the clause 6.5.16:2 is in a “Constraints” section of the C99 standard, so a conforming compiler is required to emit a diagnostic for a program that breaks the clause. It is still undefined behavior: the compiler can still do what it wants after the diagnostic is emitted. But there has to be a message. In consequence, Clang is behaving in a non-conforming manner here.

Outras dicas

const variable can't be modified after initialization, otherwise it's undefined behavior.

Since it is undefined behavior, I think one can say both gcc and clang follow the standard. (Although gcc's choice seems better, it deserves a warning) (See EDIT below)

The only way to give the variable x a value with defined behavior is to initialize it:

SX sx = { .x = 10 };

EDIT: As @Keith Thompson comments below, it's more than just undefined behavior in this case:

C99 §6.5.16 Assignment operators

Constraints

An assignment operator shall have a modifiable lvalue as its left operand.

This is a constraint, and according to:

C99 §5.1.1.3 Diagnostics

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances.

A compiler must issue a diagnostic for any program that violates a constraint.

Back to the question, gcc is correct is generate a warning, while clang fails to do so.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top