The strchr
function in the C standard library looks for a char
in a string, but its signature takes an int
for the search character. In these two implementations I found, the implementation casts this int
to a 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;
}
Does anyone know why? Why not just take a char
as a parameter?
In c the type of a character literal is
int
. For example: 'a' is of typeint
.The reasons for that are purely historical. Note, that in the old days of C language (K&R C) there was no such thing as function prototype. A
strchr
function in those times would be declared asand defined in K&R style as
However, in C language (in K&R C and in the modern one as well) if the function is declared without a prototype (as shown above), the parameters passed in each function call are subjected to so called default argument promotions. Under default argument promotions any integral type smaller than
int
(orunsigned int
) is always converted toint
(orunsigned int
). I.e. when the parameters are undeclared, whenever you pass achar
value as an argument, this value is implicitly converted toint
, and actually physically passed as anint
. The same is true forshort
. (BTW,float
is converted todouble
by default argument promotions). If inside the function the parameter is actually declared as achar
(as in the K&R style definition above), it is implicitly converted back tochar
type and used as achar
inside the function. This is how it worked in K&R times, and this actually is how it works to this day in modern C when function has no prototype or when variadic parameters are used.Now, cue in the modern C, which has function prototypes and uses modern-style function definition syntax. In order to preserve and reproduce the "traditional" functionality of
strchr
, as described above, we have no other choice but to declare the parameter ofstrchr
as anint
and explicitly convert it tochar
inside the function. This is exactly what you observe in the code you quoted. This is exactly as the functionality ofstrchr
is described in the standard.Moreover, if you have an already-compiled legacy library, where
strchr
is defined in K&R style as shown above, and you decided to provide modern prototypes for that library, the proper declaration forstrchr
would bebecause
int
is what the above legacy implementation expects to physically receive asc
. Declaring it with achar
parameter would be incorrect.For this reason, you will never see "traditional" standard library functions expecting parameters of type
char
,short
orfloat
. All these functions will be declared with parameters of typeint
ordouble
instead.A very same rationale is behind the standard guarantee that char pointers and
void *
pointers share the same representation and alignment requirements. Relying on this guarantee you can declaremalloc
as avoid *
-returning function and then use this declaration with a pre-compiled legacy version of standard library wheremalloc
actually returnedchar *
.Reference: the C99 rationale, version 5.10
I think this can be attributed to nothing more than an accident of history. You're exactly right that
char
seems the obvious data type to use for the character being searched for.In some situations in the C library, such as the
getc()
function, anint
value is returned for the character read from input. This is not achar
because an extra non-character value (EOF
, usually -1) can be returned to indicate the end of the character stream.The
EOF
case doesn't apply to thestrchr()
function, but they can't really go back and change the declaration of the function in the C library now.int c
is the character that you want to search. The character is passed as an integer, but in fact only the lower 8 bits are searched. It should therefore be handed over to a charThe
strchr
function looks like this:As you can see there is a
cast
ofint c
to(char)c
.Now to Answer to your question, your
char ch
it is converted to an integerint c
and applied as the ordinal value of a character.So the following program should be OK:
But the following not:
Because of
multi-character character constant
which isoverflow in implicit constant conversion