O que é um efeito colateral em C?

Sep 27 2020

Na cláusula C99 5.1.2.3 parágrafo 2,

Acessar um objeto volátil, modificar um objeto, modificar um arquivo ou chamar uma função que faz qualquer uma dessas operações são todos efeitos colaterais , que são mudanças no estado do ambiente de execução.

O padrão C define os efeitos colaterais como acima. Mas parece que C99 não explica o que exatamente é acessar um objeto volátil, modificar um objeto, modificar um arquivo (Está definido na cláusula 3 qual é a definição de acessar, modificar, objeto. Mas acessar um objeto volátil como? Modificar qual objeto ? e modificando o que dizer de um arquivo?).
Existem alguns exemplos no C99 conforme eu procuro com a palavra efeitos colaterais . Mas não posso ter certeza se cada um dos exemplos é classificado entre acessar um objeto volátil, modificar um objeto e modificar um arquivo.
Eu li O que é efeito colateral em c? e os efeitos colaterais são uma coisa boa? mas ainda estou confuso.
Minha pergunta é se o padrão C descreve explicitamente o significado deefeitos colaterais ? O que eles querem dizer?

Respostas

4 EricPostpischil Sep 27 2020 at 20:08

Minha pergunta é se o padrão C descreve explicitamente o significado dos efeitos colaterais?

A frase no padrão C que você cita (C 1999 5.1.2.3 2, e o mesmo em C 2018) descreve explicitamente o significado dos efeitos colaterais . Eles são explicados mais detalhadamente abaixo.

Modificando um objeto

A modificação de um objeto inclui as coisas que atualizam os bytes armazenados que representam o objeto. Acredito que uma lista completa deles é:

  • Atribuição simples ( =) e atribuição composto ( *=, /= %=, +=, -=, <<=, >>=, &=, ^=, e |=).
  • Os operadores de incremento e decremento ( ++e --), prefixo e pós-fixados.
  • Inicialização de um objeto incluído em sua definição.
  • Rotinas de biblioteca que são especificadas para alterar objetos, como memcpy.

Acessando um objeto volátil

“Acesso” é definido em C 2018 3.1 como “⟨ação em tempo de execução⟩ para ler ou modificar o valor de um objeto”. Se xfor a volatile int, usar o valor de xem uma expressão acessa (quando a expressão é avaliada), porque lê o valor de x. Você pode acompanhar isso mais especificamente em que 6.3.2.1 2 nos diz que o uso de xem uma expressão resulta no valor de xser tomado:

Exceto quando é o operando do sizeofoperador, o &operador unário , o ++operador, o --operador ou o operando esquerdo do .operador ou um operador de atribuição, um lvalue que não tem tipo de matriz é convertido para o valor armazenado no objeto designado (e não é mais um lvalue); isso é chamado de conversão de lvalue .

Assim, o xin na expressão que é, por si só, apenas uma designação do objeto x, é convertido no valor armazenado em x, o que significa que o valor armazenado é lido da memória. Esse é um acesso de x.

Modificar um objeto volátil é o mesmo que modificar qualquer objeto, descrito acima.

Modificando um arquivo

Os arquivos são modificados por meio das rotinas definidas na cláusula 7.21 (“Entrada / saída <stdio.h>”).

1 AnttiHaapala Sep 27 2020 at 20:04

Acessar um objeto volátil significa ler o valor de um volatileobjeto -qualificado / um objeto por meio de um valor-qualificado-volátil - o padrão diz que eles precisam ser avaliados " estritamente de acordo com as regras da máquina abstrata".

Modificar um objeto significa modificar qualquer objeto - modificar qualquer coisa é considerado um efeito colateral. Exemplo: um operador de atribuição tem o efeito colateral de modificar uma variável à qual atribui o valor! No programa a seguir. Um operador de atribuição é usado para seu efeito colateral!

Modificar um arquivo significa gravar no arquivo, criar um arquivo, excluir um arquivo e assim por diante - qualquer coisa que constitua uma mudança.

Exemplos de efeitos colaterais dessas categorias:

void increment(int *p) {
    (*p) ++; // side effect - assign a new value to the 
             // object pointed to by p
}


int a = 5;
volatile int b = 6;
if (b == 6) { // side-effect of accessing a volatile variable
    a += b;   // calculate a + b, and as a side effect assign a new 
              // value to a
}

increment(&a);     // side effect - call a function that does
                   // one of the aforementioned operations
printf("%d\n", a); // side effect - change the state of an output stream

FILE *fp = fopen("foo", "w"); // side effect - create or truncate
fputc('!', fp); // side effect - modify file
fclose(fp);.    // side effect - close the file, flush 
remove("bar");. // side effect - remove file

Existe uma categoria (bem menor) de linguagens de programação chamadas linguagens funcionais puras, como Haskell, cujos cálculos são livres de efeitos colaterais. C não é uma dessas linguagens.