Por que o strchr faz um int para o char ser encontrado?

A function strchr na biblioteca padrão C procura por um char em uma string, mas sua assinatura usa um int para o caractere de pesquisa. Nestas duas implementações que encontrei, a implementação converte este int para um char :

 char *strchr(const char *s, int c) { while (*s != (char)c) if (!*s++) return 0; return (char *)s; } char *strchr(const char *s, int c) { while (*s && *s != (char)c) s++; if (*s == c) return (char *)s; return NULL; } 

Alguem sabe por quê? Por que não pegar um char como parâmetro?

As razões para isso são puramente históricas. Note que nos velhos tempos da linguagem C (K & R C) não existia o protótipo de function . Uma function strchr naqueles tempos seria declarada como

 char *strchr(); 

e definido em estilo K & R como

 char *strchr(s, c) char *s; char c; { /* whatever */ } 

No entanto, na linguagem C (no K & R C e no moderno também) se a function é declarada sem um protótipo (como mostrado acima), os parâmetros passados ​​em cada chamada de function são submetidos às chamadas promoções de argumentos padrão . Em promoções de argumentos padrão, qualquer tipo integral menor que int (ou unsigned int ) é sempre convertido para int (ou unsigned int ). Ou seja, quando os parâmetros não são declarados, sempre que você passa um valor de char como um argumento, esse valor é implicitamente convertido em int e, na verdade, passado fisicamente como um int . O mesmo é verdade para short . (BTW, float é convertido em double por promoções de argumentos padrão). Se dentro da function o parâmetro é realmente declarado como um char (como na definição de estilo K & R acima), ele é implicitamente convertido de volta para o tipo char e usado como um char dentro da function. Foi assim que funcionou em tempos K & R, e é assim que funciona até hoje em C moderno quando a function não tem protótipo ou quando parâmetros variadicos são usados.

Agora, sugestão no moderno C, que tem protótipos de function e usa syntax de definição de function de estilo moderno. Para preservar e reproduzir a funcionalidade “tradicional” do strchr , como descrito acima, não temos outra escolha a não ser declarar o parâmetro strchr como um int e explicitamente convertê-lo em char dentro da function. Isso é exatamente o que você observa no código citado. Isso é exatamente como a funcionalidade do strchr é descrita no padrão.

Além disso, se você tem uma biblioteca legada já compilada, onde strchr é definido no estilo K & R como mostrado acima, e você decidiu fornecer protótipos modernos para essa biblioteca, a declaração apropriada para strchr seria

 char *strchr(const char *s, int c); 

porque int é o que a implementação herdada acima espera receber fisicamente como c . Declará-lo com um parâmetro char seria incorreto.

Por esse motivo, você nunca verá funções de biblioteca padrão “tradicionais” esperando parâmetros do tipo char , short ou float . Todas essas funções serão declaradas com parâmetros do tipo int ou double .

Um mesmo raciocínio está por trás da garantia padrão de que os pointers do tipo char e void * compartilham os mesmos requisitos de representação e alinhamento. Baseando-se nesta garantia, você pode declarar malloc como uma function void * -returning e, em seguida, usar essa declaração com uma versão legada pré-compilada da biblioteca padrão, onde malloc realmente retornou char * .


Referência: o raciocínio C99, versão 5.10

7.1.4 Uso de funções de biblioteca
/ – /
Todos os protótipos de bibliotecas são especificados em termos dos tipos “ampliados”: um argumento anteriormente declarado como char agora é escrito como int. Isso garante que a maioria das funções da biblioteca possa ser chamada com ou sem um protótipo no escopo, mantendo assim a compatibilidade retroativa com o código pré-C89

Eu acho que isso pode ser atribuído a nada mais do que um acidente da história. Você está exatamente certo de que char parece o tipo de dados óbvio a ser usado para o personagem que está sendo pesquisado.

Em algumas situações na biblioteca C, como a function getc() , um valor int é retornado para o caractere lido da input. Isso não é um char porque um valor extra sem caractere ( EOF , geralmente -1) pode ser retornado para indicar o final do stream de caracteres.

O caso EOF não se aplica à function strchr() , mas eles não podem realmente voltar e alterar a declaração da function na biblioteca C agora.

Em c, o tipo de um literal de caractere é int . Por exemplo: ‘a’ é do tipo int .

int c é o caractere que você deseja pesquisar. O caractere é passado como um inteiro, mas na verdade apenas os 8 bits inferiores são pesquisados. Deve, portanto, ser entregue a um char

A function strchr é assim:

 char *strchr(const char *s, int c){ while (*s != (char)c) if (!*s++) return 0; return (char *)s; } 

Como você pode ver, há um cast de int c para (char)c .

Agora, para responder à sua pergunta, seu char ch é convertido em um inteiro int c e aplicado como o valor ordinal de um caractere.

Então o seguinte programa deve estar OK:

 #include #include int main(void){ char *name = "Michi"; int c = 99; /* 99 is the ANSI code of c*/ char *ret = strchr(name, c); printf("String after %s\n", ret); return 0; } 

Mas o seguinte não:

 #include #include int main(void){ char *name = "Michi"; char c = '99'; /* 99 is the ANSI code of c*/ char *ret = strchr(name, c); printf("String after %s\n", ret); return 0; } 

Por causa da multi-character character constant de multi-character character constant que está overflow in implicit constant conversion