c++ - resolvidos - Comportamento indefinido, não especificado e definido pela implementação




programação orientada a objetos c++ exercicios resolvidos (6)

Qual é a diferença entre o comportamento indefinido, não especificado e definido pela implementação em C e C ++?


Bem, isso é basicamente um copiar-colar direto do padrão

3.4.1 Comportamento não especificado de comportamento definido pela implementação, onde cada implementação documenta como a escolha é feita

2 EXEMPLO Um exemplo de comportamento definido pela implementação é a propagação do bit de alta ordem quando um inteiro com sinal é deslocado para a direita.

3.4.3 1 comportamento comportamental indefinido , mediante a utilização de uma construção de programa não transportável ou errônea ou de dados errados, para os quais esta Norma não impõe requisitos

2 OBSERVAÇÃO Possível comportamento indefinido varia de ignorar completamente a situação com resultados imprevisíveis, comportar-se durante a tradução ou execução do programa de uma maneira documentada característica do ambiente (com ou sem emissão de uma mensagem de diagnóstico), terminar uma tradução ou execução (com a emissão de uma mensagem de diagnóstico).

3 EXEMPLO Um exemplo de comportamento indefinido é o comportamento no estouro de inteiro.

3.4.4 Uso de um comportamento não especificado de um valor não especificado, ou outro comportamento em que esta Norma Internacional fornece duas ou mais possibilidades e não impõe mais requisitos sobre qual é escolhido em qualquer instância

2 EXEMPLO Um exemplo de comportamento não especificado é a ordem na qual os argumentos para uma função são avaliados.


Do documento oficial do Racional C

Os termos comportamento não especificado , comportamento indefinido e comportamento definido pela implementação são usados ​​para categorizar o resultado de programas de gravação cujas propriedades o Padrão não descreve completamente. O objetivo de adotar essa categorização é permitir uma certa variedade entre implementações que permitam que a qualidade da implementação seja uma força ativa no mercado, bem como permitir certas extensões populares, sem remover o hiato de conformidade com o Padrão. O Apêndice F ao Padrão cataloga os comportamentos que se enquadram em uma dessas três categorias.

Comportamento não especificado fornece ao implementador alguma latitude na tradução de programas. Essa latitude não se estende a ponto de não conseguir traduzir o programa.

Comportamento indefinido fornece a licença do implementador para não detectar certos erros de programa que são difíceis de diagnosticar. Ele também identifica áreas de possível extensão de linguagem em conformidade: o implementador pode aumentar a linguagem fornecendo uma definição do comportamento oficialmente indefinido.

O comportamento definido pela implementação fornece ao implementador a liberdade de escolher a abordagem apropriada, mas exige que essa escolha seja explicada ao usuário. Comportamentos designados como definidos pela implementação geralmente são aqueles em que um usuário pode tomar decisões de codificação significativas com base na definição de implementação. Os implementadores devem ter em mente este critério ao decidir quão extensa uma definição de implementação deveria ser. Como no comportamento não especificado, simplesmente não traduzir a fonte que contém o comportamento definido pela implementação não é uma resposta adequada.


Historicamente, tanto Comportamento Definido por Implementação como Comportamento Indefinido representavam situações em que os autores do Padrão esperavam que as pessoas que escrevessem implementações de qualidade usassem de julgamento para decidir quais garantias comportamentais seriam úteis para programas no campo de aplicação pretendido em execução no alvos pretendidos. As necessidades do código high-end number-crunching são bem diferentes das do código de sistemas de baixo nível, e tanto o UB quanto o IDB dão flexibilidade aos escritores de compiladores para atender a essas diferentes necessidades. Nenhuma das categorias determina que as implementações se comportem de maneira útil para qualquer propósito específico, ou mesmo para qualquer finalidade. Implementações de qualidade que afirmam ser adequadas para uma finalidade específica, no entanto, devem comportar-se de maneira condizente com tal propósito, quer a Norma exija ou não .

A única diferença entre Comportamento Definido por Implementação e Comportamento Indefinido é que o primeiro exige que as implementações definam e documentem um comportamento consistente mesmo em casos em que nada que a implementação poderia fazer seria útil . A linha divisória entre eles não é se seria geralmente útil para implementações definir comportamentos (escritores de compiladores deveriam definir comportamentos úteis quando prático se o Padrão os requer ou não) mas se haveria implementações onde definir um comportamento seria simultaneamente caro e inútil . Um julgamento de que tais implementações possam existir não de forma alguma, forma ou formulário, implica qualquer julgamento sobre a utilidade de suportar um comportamento definido em outras plataformas.

Infelizmente, desde meados da década de 1990, escritores de compiladores começaram a interpretar a falta de mandatos comportamentais como um julgamento de que garantias comportamentais não valem o custo, mesmo em campos de aplicação onde eles são vitais, e até mesmo em sistemas onde eles custam praticamente nada. Em vez de tratar a UB como um convite para exercer um julgamento razoável, os escritores de compiladores começaram a tratá-la como uma desculpa para não fazê-lo.

Por exemplo, dado o seguinte código:

int scaled_velocity(int v, unsigned char pow)
{
  if (v > 250)
    v = 250;
  if (v < -250)
    v = -250;
  return v << pow;
}

a implementação de um complemento de dois não teria que gastar qualquer esforço para tratar a expressão v << pow como uma mudança do complemento de dois sem considerar se v era positivo ou negativo.

A filosofia preferida entre alguns dos escritores atuais do compilador, no entanto, sugeriria que, porque v só pode ser negativo se o programa for se envolver em Comportamento Indefinido, não há razão para que o programa retenha o intervalo negativo de v . Embora os valores negativos de deslocamento para a esquerda costumem ser suportados em cada compilador de significância, e uma grande quantidade de código existente depende desse comportamento, a filosofia moderna interpretaria o fato de que o Padrão diz que os valores negativos de deslocamento à esquerda são UB como implicando que os escritores do compilador devem se sentir livres para ignorar isso.


Implementação definida

Os implementadores desejam, devem ser bem documentados, o padrão dá escolhas, mas é certo compilar

Não especificado -

Mesmo que definido pela implementação, mas não documentado

Indefinido-

Tudo pode acontecer, cuidar disso.


Talvez a redação fácil possa ser mais fácil de entender do que a definição rigorosa dos padrões.

comportamento definido pela implementação
A linguagem diz que temos tipos de dados. Os fornecedores de compiladores especificam quais tamanhos eles devem usar e fornecem uma documentação do que eles fizeram.

comportamento indefinido
Você está fazendo algo errado. Por exemplo, você tem um valor muito grande em um int que não cabe no char . Como você coloca esse valor em char ? na verdade não tem jeito! Qualquer coisa poderia acontecer, mas a coisa mais sensata seria pegar o primeiro byte desse int e colocá-lo em char . É errado fazer isso para atribuir o primeiro byte, mas isso é o que acontece sob o capô.

comportamento não especificado
Qual função desses dois é executada primeiro?

void fun(int n, int m);

int fun1()
{
  cout << "fun1";
  return 1;
}
int fun2()
{
  cout << "fun2";
  return 2;
}
...
fun(fun1(), fun2()); // which one is executed first?

A linguagem não especifica a avaliação, da esquerda para a direita ou da direita para a esquerda! Assim, um comportamento não especificado pode ou não resultar em um comportamento indefinido, mas certamente seu programa não deve produzir um comportamento não especificado.

@eSKay Eu acho que sua pergunta vale a pena editar a resposta para esclarecer mais :)

por fun(fun1(), fun2()); não é o comportamento "implementação definida"? O compilador tem que escolher um ou outro curso, afinal de contas?

A diferença entre implementação definida e não especificada, é que o compilador deve escolher um comportamento no primeiro caso, mas não é necessário no segundo caso. Por exemplo, uma implementação deve ter uma e apenas uma definição de sizeof(int) . Portanto, não é possível dizer que sizeof(int) é 4 para uma parte do programa e 8 para outros. Ao contrário do comportamento não especificado, onde o compilador pode dizer OK, eu vou avaliar esses argumentos da esquerda para a direita e os argumentos da próxima função são avaliados da direita para a esquerda. Pode acontecer no mesmo programa, por isso é chamado de não especificado . Na verdade, o C ++ poderia ter sido facilitado se alguns dos comportamentos não especificados fossem especificados. Dê uma olhada aqui na resposta do Dr. Stroustrup para isso :

Alega-se que a diferença entre o que pode ser produzido dando ao compilador essa liberdade e exigindo "avaliação ordinária da esquerda para a direita" pode ser significativa. Não estou convencido, mas com inúmeros compiladores "lá fora" aproveitando a liberdade e algumas pessoas defendendo apaixonadamente essa liberdade, uma mudança seria difícil e poderia levar décadas para penetrar nos cantos distantes dos mundos C e C ++. Eu estou desapontado que nem todos os compiladores avisam contra código como ++ i + i ++. Da mesma forma, a ordem de avaliação dos argumentos não é especificada.

Na IMO, muitas "coisas" são deixadas indefinidas, não especificadas, definidas pela implementação etc. No entanto, é fácil dizer e até dar exemplos, mas é difícil de corrigir. Também deve ser notado que não é tão difícil evitar a maioria dos problemas e produzir código portátil.


Comportamento indefinido versus comportamento não especificado tem uma breve descrição dele.

Seu resumo final:

Resumindo, o comportamento não especificado é geralmente algo com o qual você não deve se preocupar, a menos que seu software precise ser portátil. Por outro lado, o comportamento indefinido é sempre indesejável e nunca deve ocorrer.





unspecified-behavior