Isto é de preferência :
Os operandos esquerdos dos operadores de atribuição devem ser expressões unárias (não convertidas de nível 2).
Essa página de referência tem 2 ocorrências de "level", ou seja, a outra é "precedence level". Mas o nível de precedência 1 tem "Function call" e o nível de precedência 2 tem "sizeof", aos quais não é possível atribuir algo.
Posso entender "não-cast" porque cast pode converter lvalue em rvalue .
Então o que significa esse "nível 2"?
A referência ao “nível 2” é uma referência à linha rotulada “2” na coluna Precedência na tabela anterior.
Este “nível” é uma invenção do cppreference.com; não faz parte do padrão C. (E, portanto, é uma das razões pelas quais o cppreference.com não é uma boa referência.) O padrão C não especifica precedências por níveis ou uma tabela. A precedência é construída na gramática formal da linguagem.
Na gramática formal C, uma expressão de conversão é uma das seguintes:
(
tipo-nome-)
expressão-de-castUma expressão unária é uma das seguintes:
++
expressão unária--
expressão unária&
,*
,+
,-
,~
, ou!
sizeof
expressão unáriasizeof
(
nome-do-tipo)
alignof
(
nome-do-tipo)
Comparando-os com a tabela cppreference.com, vemos que seus itens de nível de precedência dois são todos os operadores de uma unary-expression (omitindo a operator-less postfix-expression ) mais o operador de conversão. Portanto, a unary-expression do padrão C corresponde a todos os operadores de nível 2 do cppreference.com, exceto a conversão. É isso que o cppreference.com quer dizer com "level-2 non-cast"; pegar seus operadores de nível 2 e remover a conversão deixa os operadores "unary". (Cast é um operador unary no sentido comum de "unary", mas não está incluído no token unary-expression na gramática formal C. É isso que impede
sizeof (int) * p
que seja interpretado comosizeof ( (int *) p )
instead of(sizeof (int)) * p
, que é mencionado, mas não explicado, na nota 2 do cppreference.com.)A declaração do cppreference.com de que “Os operandos esquerdos dos operadores de atribuição devem ser expressões unárias (não convertidas de nível 2)” refere-se ao fato de que, na gramática formal C, uma expressão de atribuição é uma das seguintes:
Assim, a gramática exige que o operando esquerdo de um operador de atribuição seja uma expressão unária .
Este não é o único requisito no operando esquerdo de um operador de atribuição. C 2024 6.5.17.1 também declara:
Isso não faz parte da gramática formal. É declarado separadamente como uma restrição. Então o operando esquerdo de um operador de atribuição deve ser uma expressão unária e deve ser um lvalue modificável.