Por que o alfabeto é dividido em vários intervalos neste código C?

161

Em uma biblioteca personalizada, vi uma implementação:

inline int is_upper_alpha(char chValue)
{
    if (((chValue >= 'A') && (chValue <= 'I')) ||
        ((chValue >= 'J') && (chValue <= 'R')) ||
        ((chValue >= 'S') && (chValue <= 'Z')))
        return 1;
    return 0;
}

Isso é um ovo de Páscoa ou quais são as vantagens do método C / C ++ padrão?

inline int is_upper_alpha(char chValue)
{
    return ((chValue >= 'A') && (chValue <= 'Z'));
}
Vladimir Ch.
fonte
Observe que no EBCDIC, o intervalo de caracteres para letras minúsculas vem antes do intervalo de caracteres para letras maiúsculas e ambos antes dos dígitos - exatamente o oposto da ordem nas codificações baseadas em ASCII (como o 8859- série x, ou Unicode, ou CP1252, ou…).
Jonathan Leffler
1
Nota: se 'J' - 'I'e 'S' - 'R'ambos iguais 1, então espero que um otimizador razoável gire o primeiro no segundo.
Matthieu M.

Respostas:

214

O autor deste código, presumivelmente, tinha de apoiar EBCDIC em algum momento, em que os valores numéricos das letras são não contíguas (existem lacunas entre I, Je R, Scomo você deve ter adivinhado).

Vale a pena notar que a padrões C ++ única garantia de que os personagens C e 0para 9ter valores numéricos contíguos precisamente por essa razão, de modo nenhum desses métodos é estritamente padrão-conformidade.

Wintermute
fonte
64
O verdadeiro WTF é porque não fez o autor original colocar em um comentário: // In the EBCDIC coding, the alphabet has gaps between these values. See URL: xxxx for details. Então você nunca precisaria fazer a pergunta. Você teria a resposta incorporada ao código.
Abelenky 5/05
66
@abelenky Se o código era originalmente para um sistema em que o ebcdic é normalmente usado, pode parecer óbvio na época e não precisa de um comentário, infelizmente as coisas que parecem boas no código legado parecem estranhas agora.
Vality
26
@abelenky: A verdadeira WTF é porque não fez o uso autor original funcionalidade padrão, ou seja return ( isalpha( chValue ) && isupper( chValue ) )...
DevSolar
4
@ Damon: Esse não é o problema. Pode ser necessário processar uma codificação "alienígena", mesmo em um sistema que não a use nativamente. Então, você define seu código de idioma para a codificação especificada e deve manter os dedos cruzados, para que o programador realmente use funções padrão em vez de codificar "inteligente" como o descrito acima, pensando que ele sabe que todas as codificações que seu programa irá encontrar ...
DevSolar
6
Se ele foi escrito para oferecer suporte ao EBCDIC a partir da década de 1970, o isalpha e o isupper são mesmo ANSI ou suportados pela maioria dos compiladores na época?
nickalh
54

Parece que ele tenta cobrir tanto o EBCDIC quanto o ASCII. Seu método alternativo não funciona para EBCDIC (ele possui falsos positivos, mas nenhum falso negativo)

C e C ++ que exigem que '0'-'9'são contíguos.

Observe que a biblioteca padrão chama não sei se eles são executados em ASCII, EBCDIC ou outros sistemas, por isso eles são mais portáteis e, possivelmente, mais eficiente.

MSalters
fonte
5
std::isupperrealmente consulta o código C global instalado no momento.
Lingxi 5/05
1
Sim você está certo. O método foi escrito para cobrir as duas codificações. Obrigado pela resposta!
Vladimir Ch.
4
@Lingxi: Verdade, mas isso não significa que você pode mudar o código do idioma de ASCII para EBCDIC. 'A'deve permanecer 'A'independentemente da localidade. ASCII para UTF-8, isso seria possível.
MSalters 5/05
2
@Lingxi: std::isupperconsulta o local C global atualmente instalado, sim, mas a fase de compilação que interpreta os caracteres literais não.
Lightness Races em órbita
1
@Lingxi - Apenas nota rápida. É questionável se std::isupperé realmente necessário na maioria dos casos. Ele respeita as localidades usadas para entrada do usuário. Mas ao analisar arquivos, interagindo com bancos de dados, você normalmente espera algum outro código de idioma. Além disso, pelo menos no Linux, essas chamadas relacionadas ao código do idioma são muito lentas - por exemplo, std::isalphachama dynamic_cast duas vezes para "encontrar" a implementação apropriada do código do idioma antes de comparar um único caractere.
Iate5041