Pergunta

C define pelo menos 3 níveis de "expressão constante":

  • expressão constante (não qualificada)
  • expressão de constante aritmética
  • expressão constante de número inteiro

6.6 parágrafo 3 lê:

Expressões constantes não devem conter atribuição, incremento, decremento, chamada de função, ou operadores de vírgula, exceto quando estão contidos em uma subexpressão que não é avaliado.

Então, isso significa que 1,2 não é uma expressão constante?

O parágrafo 8 diz:

Uma expressão de constante aritmética deve ter tipo aritmético e deve ter apenas operandos que são constantes inteiras, constantes flutuantes, constantes de enumeração, caractere constantes e tamanho das expressões. Operadores de conversão em uma expressão de constante aritmética deve apenas converter tipos aritméticos em tipos aritméticos, exceto como parte de um operando para um operador sizeof cujo resultado é uma constante inteira.

Quais são os operandos em (union { uint32_t i; float f; }){ 1 }.f? Se 1 for o operando, então esta é provavelmente uma expressão constante aritmética, mas se { 1 } for o operando, então claramente não é.

Editar: Outra observação interessante: 7.17 parágrafo 3 requer que o resultado de offsetof seja uma expressão constante inteira do tipo size_t, mas as implementações padrão de offsetof, até onde posso dizer, não são devem ser expressões constantes inteiras pelo padrão. É claro que isso está certo, pois uma implementação é permitida (sob 6.6 parágrafo 10) para aceitar outras formas de expressões constantes, ou implementar a macro offsetof como __builtin_offsetof em vez de por meio de subtração de ponteiro. A essência desta observação, entretanto, é que se você deseja usar offsetof em um contexto onde uma expressão constante de inteiro é necessária, você realmente precisa usar a macro fornecida pela implementação e não fazer a sua própria.

Foi útil?

Solução

Com base na sua leitura, 1,2 não é uma expressão constante. Não sei por que não é, só que concordo com você que não é (apesar do fato de que provavelmente deveria ser).

6.5.2 especifica literais compostos como um operador postfix. Então, em

(union { uint32_t i; float f; }){ 1 }.f

Os operandos são (union { uint32_t i; float f; }){ 1 } e f para o operador .. Não é uma expressão constante aritmética, já que o primeiro argumento é um tipo union, mas é uma expressão constante.

ATUALIZAÇÃO: eu estava baseando isso em uma interpretação diferente do padrão.

Meu raciocínio anterior era que (union { uint32_t i; float f; }){ 1 }.f atendia aos critérios para uma expressão constante e, portanto, era uma expressão constante. Ainda acho que atende aos critérios para uma expressão constante (6,6 parágrafo 3), mas não é nenhum dos tipos padrão de expressões constantes (inteiro, aritmética ou endereço) e, portanto, está sujeito a ser uma expressão constante apenas por 6,6 parágrafo 10, que permite expressões constantes definidas pela implementação.

Eu também queria chegar à sua edição. Eu ia argumentar que a implementação "hack" de offsetof era uma expressão constante, mas acho que é o mesmo que acima: ela atende aos critérios para uma expressão constante (e possivelmente uma constante de endereço), mas não é uma expressão constante inteira, e é, portanto, inválido fora do 6.6 parágrafo 10.

Outras dicas

Se 1,2 fosse uma expressão constante, isso permitiria que um código como este fosse compilado:

{ // code        // How the compiler interprets:
  int a[10, 10]; // int a[10];

  a[5, 8] = 42;  // a[8] = 42;
}

Não sei se é o verdadeiro motivo, mas posso imaginar que emitir um erro para esse erro (comum?) fosse considerado mais importante do que transformar 1,2 em uma expressão constante.

ATUALIZAÇÃO : como R. aponta em um comentário, o código sobre não é mais um erro do compilador desde a introdução dos VLAs.

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