Recentemente, encontrei algo semelhante às seguintes linhas:
#include <string>
// test if the extension is either .bar or .foo
bool test_extension(const std::string& ext) {
return ext == ".bar" || ".foo";
// it obviously should be
// return ext == ".bar" || ext == ".foo";
}
Obviamente, a função não faz o que o comentário sugere. Mas esse não é o ponto aqui. Observe que esta não é uma duplicata de Você pode usar 2 ou mais condições OR em uma instrução if? desde que eu estou ciente de como você escreveria a função corretamente!
Comecei a me perguntar como um compilador poderia tratar esse trecho. Minha primeira intuição seria que isso seria compilado return true;
basicamente. Ao incluir o exemplo no godbolt , mostrou que nem o GCC 9.2 nem o clang 9 fazem essa otimização com otimização -O2
.
No entanto, alterar o código para 1
#include <string>
using namespace std::string_literals;
bool test_extension(const std::string& ext) {
return ext == ".bar"s || ".foo";
}
parece fazer o truque, já que a montagem agora é essencialmente:
mov eax, 1
ret
Então, minha pergunta principal é: existe algo que eu perdi que não permite que um compilador faça a mesma otimização no primeiro trecho?
1 Com ".foo"s
isso nem compilaria, pois o compilador não deseja converter um std::string
para bool
;-)
Editar
O seguinte trecho de código também é otimizado "corretamente" para return true;
:
#include <string>
bool test_extension(const std::string& ext) {
return ".foo" || ext == ".bar";
}
operator==(string const&, string const&)
seja noexcept
enquanto operator==(string const&, char const*)
não é? Não tenho tempo para aprofundar isso agora.
foo || ext == ".bar"
, a chamada é otimizada (consulte editar). Isso contradiz sua teoria?
a || b
significa "avaliar a expressão b
apenas se a expressão a
for false
". É ortogonal ao tempo de execução ou tempo de compilação. true || foo()
pode ser otimizado para true
, mesmo que foo()
tenha efeitos colaterais, porque (não importa se otimizado ou não) o lado direito nunca é avaliado. Mas foo() || true
não pode ser otimizado, a true
menos que o compilador possa provar que a chamada foo()
não tem efeitos colaterais observáveis.
xor eax,eax
, embora sem essa opção chame a função de comparação de cadeias. Não tenho ideia do que fazer com isso.
string::compare(const char*)
tem alguns efeitos colaterais que o compilador não eliminará (queoperator==(string, string)
não possui)? Parece improvável, mas o compilador já determinou que o resultado é sempre verdadeiro (também temmov eax, 1
ret
) mesmo para o primeiro trecho.