为什么 strchr 采用 int 来查找 char?

发布于 2024-08-24 02:50:14 字数 513 浏览 2 评论 0原文

C 标准库中的 strchr 函数在字符串中查找 char,但其签名采用 int 作为搜索字符。在我发现的这两个实现中,该实现将此 int 转换为 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;
}

有人知道为什么吗?为什么不直接使用 char 作为参数呢?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

懒的傷心 2024-08-31 02:50:14

其原因纯粹是历史原因。请注意,在过去的 C 语言(K&RC)中,没有函数原型这样的东西。那时的 strchr 函数将被声明为

char *strchr();

K&R 风格并定义为

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

然而,在 C 语言中(在 K&RC 和现代语言中),如果该函数声明时没有原型(如上所示),每个函数调用中传递的参数都会受到所谓的默认参数提升。在默认参数提升下,任何小于 int (或 unsigned int)的整数类型始终转换为 int (或 unsigned int)代码>)。即当参数未声明时,每当您传递 char 值作为参数时,该值都会隐式转换为 int,并且实际上以物理方式传递作为一个intshort 也是如此。 (顺便说一句,float 通过默认参数提升转换为 double)。如果在函数内部参数实际上被声明为 char(如上面的 K&R 样式定义中所示),则它会隐式转换回 char code> 类型并在函数内用作 char。这就是它在 K&R 时代的工作原理,实际上这也是它在现代 C 语言中的工作原理,当函数没有原型或使用可变参数时。

现在,在现代 C 中提示,它具有函数原型并使用现代风格的函数定义语法。为了保留和重现 strchr 的“传统”功能,如上所述,我们别无选择,只能将 strchr 的参数声明为 int 并在函数内将其显式转换为 char。这正是您在引用的代码中观察到的。这与标准中描述的 strchr 功能完全相同。

此外,如果您有一个已经编译的遗留库,其中 strchr 是按照 K&R 风格定义的,如上所示,并且您决定为该库提供现代原型,则 的正确声明strchr

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

因为 int 是上述遗留实现期望以 c 形式物理接收的内容。使用 char 参数声明它是不正确的。

因此,您永远不会看到“传统”标准库函数需要 charshortfloat 类型的参数。所有这些函数都将使用 intdouble 类型的参数来声明。

char 指针和 void * 指针共享相同的表示和对齐要求的标准保证背后有一个非常相同的基本原理。依靠此保证,您可以将 malloc 声明为 void * 返回函数,然后将此声明与标准库的预编译遗留版本一起使用,其中 malloc< /code> 实际上返回了 char *


参考:C99基本原理,版本5.10

7.1.4 库函数的使用
/--/
所有库原型都是根据“扩展”类型指定的:
以前声明为 char 的参数现在写为 int。这
确保大多数库函数都可以使用或不使用
范围内的原型,从而保持向后兼容性
C89 之前的代码

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 as

char *strchr();

and defined in K&R style as

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

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 (or unsigned int) is always converted to int (or unsigned int). I.e. when the parameters are undeclared, whenever you pass a char value as an argument, this value is implicitly converted to int, and actually physically passed as an int. The same is true for short. (BTW, float is converted to double by default argument promotions). If inside the function the parameter is actually declared as a char (as in the K&R style definition above), it is implicitly converted back to char type and used as a char 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 of strchr as an int and explicitly convert it to char inside the function. This is exactly what you observe in the code you quoted. This is exactly as the functionality of strchr 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 for strchr would be

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

because int is what the above legacy implementation expects to physically receive as c. Declaring it with a char parameter would be incorrect.

For this reason, you will never see "traditional" standard library functions expecting parameters of type char, short or float. All these functions will be declared with parameters of type int or double 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 declare malloc as a void *-returning function and then use this declaration with a pre-compiled legacy version of standard library where malloc actually returned char *.


Reference: the C99 rationale, version 5.10

7.1.4 Use of library functions
/--/
All library prototypes are specified in terms of the “widened” types:
an argument formerly declared as char is now written as int. This
ensures that most library functions can be called with or without a
prototype in scope, thus maintaining backwards compatibility with
pre-C89 code

清风夜微凉 2024-08-31 02:50:14

我想这只能归咎于历史的偶然。您说得完全正确, char 似乎是用于搜索字符的明显数据类型。

在 C 库中的某些情况下,例如 getc() 函数,会为从输入读取的字符返回一个 int 值。这不是 char,因为可以返回额外的非字符值(EOF,通常为 -1)来指示字符流的结尾。

EOF 情况不适用于 strchr() 函数,但他们现在无法真正返回并更改 C 库中函数的声明。

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, an int value is returned for the character read from input. This is not a char 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 the strchr() function, but they can't really go back and change the declaration of the function in the C library now.

戒ㄋ 2024-08-31 02:50:14

在c 中,字符文字的类型是int。例如:“a”的类型为int

In c the type of a character literal is int. For example: 'a' is of type int.

朕就是辣么酷 2024-08-31 02:50:14

int c 是您要搜索的字符。字符作为整数传递,但实际上只搜索低 8 位。因此,应该将其移交给 char

strchr 函数如下所示:

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

正如您所看到的,有 int ccaststrchr 。代码>(char)c。

现在回答您的问题,您的 char ch 它被转换为整数 int c 并用作字符的序数值。

所以下面的程序应该没问题:

#include<stdio.h>
#include<string.h>

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;
}

但是下面的程序不行:

#include<stdio.h>
#include<string.h>

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;
}

因为多字符字符常量,这是隐式常量转换中的溢出

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 char

The strchr function looks like this:

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

As you can see there is a cast of int c to (char)c.

Now to Answer to your question, your char ch it is converted to an integer int c and applied as the ordinal value of a character.

So the following program should be OK:

#include<stdio.h>
#include<string.h>

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;
}

But the following not:

#include<stdio.h>
#include<string.h>

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;
}

Because of multi-character character constant which is overflow in implicit constant conversion

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文