O que o ,
operador faz em C?
c
operators
comma-operator
lillq
fonte
fonte
Respostas:
A expressão:
A primeira expressão1 é avaliada, depois a expressão2 é avaliada e o valor da expressão2 é retornado para toda a expressão.
fonte
i
os valores 5, 4, 3, 2 ou 1. É simplesmente 0. É praticamente inútil, a menos que as expressões tenham efeitos colaterais.i = b, c;
é equivalente a(i = b), c
porque porque a atribuição=
tem precedência mais alta que o operador de vírgula,
. O operador de vírgula tem a menor precedência de todas.expression1, expression2;
primeiroexpression1
é avaliada, presumivelmente por seus efeitos colaterais (como chamar uma função), depois há um ponto de sequência, depoisexpression2
é avaliado e o valor retornado ...Eu já vi usado mais em
while
loops:Ele fará a operação e, em seguida, fará um teste com base em um efeito colateral. A outra maneira seria fazê-lo assim:
fonte
while (read_string(s) && s.len() > 5)
. Obviamente, isso não funcionaria seread_string
não tivesse um valor de retorno (ou não tivesse um valor significativo). (Edit: Desculpe, não percebeu quantos anos este post foi.)while (1)
com umabreak;
declaração no corpo. Tentar forçar a parte inicial do código para o teste while ou para o teste do while, geralmente é um desperdício de energia e torna o código mais difícil de entender.while(1)
ebreak
;O operador de vírgula avaliará o operando esquerdo, descartará o resultado e, em seguida, avaliará o operando direito e esse será o resultado. O uso idiomático, conforme observado no link, é ao inicializar as variáveis usadas em um
for
loop e fornece o seguinte exemplo:Caso contrário, não existem muitos usos excelentes do operador de vírgula , embora seja fácil abusar para gerar código difícil de ler e manter.
No rascunho da norma C99, a gramática é a seguinte:
e o parágrafo 2 diz:
A nota de rodapé 97 diz:
o que significa que você não pode atribuir ao resultado do operador de vírgula .
É importante observar que o operador de vírgula tem a menor precedência e, portanto, há casos em que o uso
()
pode fazer uma grande diferença, por exemplo:terá a seguinte saída:
fonte
O operador de vírgula combina as duas expressões de ambos os lados em uma, avaliando-as na ordem da esquerda para a direita. O valor do lado direito é retornado como o valor de toda a expressão.
(expr1, expr2)
é como,{ expr1; expr2; }
mas você pode usar o resultado deexpr2
uma chamada ou atribuição de função.É frequentemente visto em
for
loops para inicializar ou manter várias variáveis como esta:Além disso, eu só o usei "com raiva" em outro caso, ao encerrar duas operações que devem sempre ir juntas em uma macro. Tínhamos código que copiava vários valores binários em um buffer de bytes para enviar em uma rede e mantinha um ponteiro onde tínhamos chegado:
Onde os valores eram
short
s ouint
s, fizemos o seguinte:Mais tarde, lemos que esse C não era realmente válido, porque
(short *)ptr
não é mais um valor l e não pode ser incrementado, embora nosso compilador na época não se importasse. Para corrigir isso, dividimos a expressão em duas:No entanto, essa abordagem contou com todos os desenvolvedores lembrando de colocar as duas declarações o tempo todo. Queríamos uma função na qual você pudesse passar o ponteiro de saída, o valor ee o tipo do valor. Sendo C, não C ++ com modelos, não poderíamos ter uma função de um tipo arbitrário, por isso decidimos por uma macro:
Ao usar o operador vírgula, pudemos usá-lo em expressões ou como instruções, conforme desejávamos:
Não estou sugerindo que nenhum desses exemplos seja de bom estilo! Na verdade, eu me lembro do Code Complete de Steve McConnell desaconselhando o uso de operadores de vírgula em um
for
loop: para facilitar a leitura e a manutenção, o loop deve ser controlado por apenas uma variável e as expressões nafor
própria linha devem conter apenas código de controle de loop, não outros bits extras de inicialização ou manutenção de loop.fonte
Isso causa a avaliação de várias instruções, mas usa apenas a última como um valor resultante (rvalue, acho).
Assim...
deve resultar em x sendo definido como 8.
fonte
Como as respostas anteriores afirmaram, avalia todas as declarações, mas usa a última como o valor da expressão. Pessoalmente, só achei útil em expressões de loop:
fonte
O único lugar que eu vi ser útil é quando você escreve um loop funky em que deseja fazer várias coisas em uma das expressões (provavelmente a expressão init ou a expressão loop. Algo como:
Perdoe-me se houver algum erro de sintaxe ou se misturei algo que não seja estrito C. Não estou argumentando que o operador é uma boa forma, mas é para isso que você pode usá-lo. No caso acima, eu provavelmente usaria um
while
loop para que as múltiplas expressões em init e loop fossem mais óbvias. (E eu inicializaria i1 e i2 inline em vez de declarar e depois inicializar ... blá blá blá.)fonte
Estou revivendo isso simplesmente para responder a perguntas de @Rajesh e @JeffMercado, que eu acho muito importantes, pois esse é um dos principais hits do mecanismo de pesquisa.
Pegue o seguinte trecho de código, por exemplo
Irá imprimir
O
i
caso é tratado como explicado pela maioria das respostas. Todas as expressões são avaliadas na ordem da esquerda para a direita, mas apenas a última é atribuídai
. O resultado da(
expressão )is
1`.O
j
caso segue regras de precedência diferentes, pois,
possui a menor precedência do operador. Devido a essas regras, o compilador vê atribuição-expressão, constante, constante ... . As expressões são novamente avaliadas na ordem da esquerda para a direita e seus efeitos colaterais permanecem visíveis, portanto,j
é o5
resultado dej = 5
.De maneira interessante,
int j = 5,4,3,2,1;
não é permitido pelas especificações de idioma. Um inicializador espera uma expressão de atribuição para que um,
operador direto não seja permitido.Espero que isto ajude.
fonte