Por que o tipo booleano no C ++ suporta ++, mas não -?

29

Por que o operador --não existe para bool, enquanto existe para o operador ++?

Eu tentei em C ++ e não sei se minha pergunta se aplica a outro idioma. Ficarei feliz em saber também.

Eu sei , posso usar o operador ++com um bool. Torna qualquer bool igual a true.

bool b = false;
b++;
// Now b == true.

Por que não podemos usar o operador de --maneira oposta?

bool b = true;
b--;
// Now b == false;

Não é muito útil, mas estou curioso.

aloisdg diz Restabelecer Monica
fonte
8
Esta pergunta no StackOverflow pode ser esclarecedora.
Blrfl
Então, a razão da história. Obrigado pelo link. Você pode escrever uma resposta e eu a coloco como resolvida?
Aloisdg diz Restabelecer Monica
Somente os links não dão boas respostas, e não há um bom mecanismo para marcar essa questão como duplicada de algo em outro site SE.
Blrfl
1
Portanto, devemos abrir um tópico no meta.stackexchange.com ou algo assim. Eu acho que você deve obter algum carma pelo bom link e se alguém o aprovar, o autor da resposta original deve obter algum carma. De fato, a pergunta original também deveria receber algum carma.
Aloisdg diz Restabelecer Monica
2
Os dups entre sites @aloisdg são um problema antigo no MSO. Siga as perguntas vinculadas para ter uma visão mais completa.

Respostas:

53

Nos velhos tempos de C, não havia tipo booleano. As pessoas usavam o intarquivo para armazenar dados booleanos, e eles funcionavam principalmente. Zero era falso e tudo o mais era verdade.

Isso significava que se você fizesse uma int flag = 0;e depois fizesse flag++o valor seria verdadeiro. Isso funcionaria independentemente do valor do sinalizador (a menos que você o fizesse muito, ele rolou e você voltou a zero, mas vamos ignorá-lo) - incrementar o sinalizador quando seu valor era 1 daria 2, o que ainda era verdade.

Algumas pessoas usaram isso para definir incondicionalmente um valor booleano como true. Não tenho certeza se alguma vez se tornou idiomático , mas está em algum código.

Isso nunca funcionou --, porque se o valor fosse diferente de 1 (o que poderia ser), o valor ainda não seria falso. E se já era false ( 0) e você fez um operador de decréscimo, não permaneceria falso.

Ao mover o código de C para C ++ nos primeiros dias, era muito importante que o código C incluído no C ++ ainda pudesse funcionar. E assim, na especificação para C ++ (seção 5.2.6 (na página 71)), ele lê:

O valor obtido pela aplicação de um postfix ++ é o valor que o operando possuía antes de aplicar o operador. [Nota: o valor obtido é uma cópia do valor original] O operando deve ser um valor modificável. O tipo do operando deve ser um tipo aritmético ou um ponteiro para um tipo de objeto completo. Depois que o resultado é observado, o valor do objeto é modificado adicionando 1 a ele, a menos que o objeto seja do tipo e bool, nesse caso, seja definido como true. [Nota: esse uso foi descontinuado, consulte o anexo D.]

O operando do postfix - é decrementado de forma análoga ao operador postfix ++, exceto que o operando não deve ser do tipo bool.

Isso é mencionado novamente na seção 5.3.2 (para o operador de prefixo - o 5.2.6 estava no postfix)

Como você pode ver, isso foi preterido (anexo D no documento, página 709) e não deve ser usado.

Mas é por isso. E às vezes você pode ver o código. Mas não faça isso.

Comunidade
fonte
5
"Algumas pessoas usaram isso para definir incondicionalmente um valor booleano como true". Vamos chamá-los de idiotas, não pessoas.
Deduplicator
@ Reduplicador: Talvez fosse uma questão de desempenho: carregar um valor em uma variável pode ter levado mais ciclos do processador do que incrementar a variável. Obviamente, isso provavelmente não importa em computadores modernos.
Giorgio
1
@ Giorgio isso é bastante provável. Lembre-se de que C foi escrito para coincidir com o conjunto de instruções do PDP-7 e o PDP-11 teve outros ajustes. A partir disso - "As pessoas costumam adivinhar que foram criadas para usar os modos de endereço de incremento automático e decremento automático fornecidos pelo DEC PDP-11 nos quais o C e o Unix se tornaram populares. Isso é historicamente impossível, pois não havia PDP- 11 quando B. foi desenvolvido. O PDP-7, no entanto, tinha algumas células de memória com 'auto incremento', com a propriedade que uma referência indireta de memória através delas incrementou a célula. "
@Duplicador: No código que usa números inteiros para booleanos, uma variável que é incrementada para cada ... o que quer que seja ... pode atuar tanto como um contador (quantas vezes foi incrementado) quanto como um booleano (foi incrementado ou não).
Keith Thompson
2

Para lidar parcialmente com o código legado usado intou semelhante ao seu tipo booleano.

Mike Graham
fonte
1
Minha pergunta é uma duplicata daqui stackoverflow.com/questions/3450420/… . A propósito, obrigado pela sua resposta.
Aloisdg diz Reinstate Monica
1

Para entender o significado histórico desta questão, você deve considerar o caso do Therac-25. O Therac-25 era um dispositivo médico que transmitia radiação a pacientes com câncer. Foi atormentado por más práticas de programação que contribuíram para seu histórico de segurança insuficiente (com várias mortes atribuídas a ele).

http://courses.cs.vt.edu/professionalism/Therac_25/Therac_1.html

(vá para o final da página 3)

Cada passagem pela rotina de teste de configuração aumenta a verificação da posição do colimador superior, uma variável compartilhada chamada Class3. Se a Classe3 for diferente de zero, há uma inconsistência e o tratamento não deve prosseguir. Um valor zero para a Classe3 indica que os parâmetros relevantes são consistentes com o tratamento e o feixe não é inibido.

...

Durante a configuração da máquina, o Teste de Configuração será executado várias centenas de vezes, pois é reprogramado, aguardando a ocorrência de outros eventos. No código, a variável Class3 é incrementada em uma em cada passagem pelo teste de configuração. Como a variável Class3 é de 1 byte, ela só pode conter um valor máximo de 255 decimal. Assim, a cada 256ª passagem pelo código do teste de configuração, a variável transborda e tem um valor zero. Isso significa que em cada 256ª passagem no teste de configuração, o colimador superior não será verificado e uma falha no colimador superior não será detectada. A superexposição ocorreu quando o operador apertou o botão "set" no momento exato em que a Class3 rolou para zero. Portanto, Chkcol não foi executado e F $ mal não foi definido para indicar que o colimador superior ainda estava na posição de luz de campo. O software ativou os 25 MeV completos sem o alvo no lugar e sem digitalização. Um feixe de elétrons altamente concentrado resultou, que foi espalhado e desviado pelo espelho de aço inoxidável que estava no caminho.

O Therac-25 usava algo como o equivalente a operator++em um bool. No entanto, a linguagem de programação que eles usaram não era C ++ e seu tipo de dados não bool. Ao contrário da garantia em C ++, no entanto, um tipo inteiro regular simplesmente continua subindo. O tipo de dados deles era equivalente a uint8_t.

O C ++ decidiu manter o ambiente operator++para pessoas acostumadas a programar assim, mas, em vez de aumentar o valor, simplesmente o define truepara evitar coisas assim.

Observe que operator++(bool)está obsoleto.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf

Anexo D de C ++ 14:

D.1 Operador de incremento com operando bool
O uso de um operando do tipo bool com o operador ++ está obsoleto (consulte 5.3.2 e 5.2.6).

David Stone
fonte
Embora isso explique por que está obsoleto, ele não explica por que existe em primeiro lugar.
Existe porque algumas pessoas definiram um valor booleano incrementando-o quando a programação em C. O C ++ foi projetado para facilitar a transição do C, portanto eles o apoiaram com o booltipo. Eu estava apenas tentando dar um exemplo histórico de quando as pessoas realmente programavam dessa maneira.
18114 David Stone