Подтвердить что ты не робот

Почему strchr принимает int для char, который нужно найти?

Функция strchr в стандартной библиотеке C ищет в строке 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 в качестве параметра?

4b9b3361

Ответ 1

Причины этого носят чисто исторический характер. Обратите внимание, что в старые времена языка C (K & R C) прототипа функции не было. Функция 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 и фактически физически передается как int. То же самое верно для short. (BTW, float преобразуется в double по умолчанию для продвижения по умолчанию). Если внутри функции параметр фактически объявлен как char (как указано выше в определении стиля K & R), он неявно преобразуется обратно в тип char и используется как char внутри функции. Вот как это работает в K & R раз, и на самом деле это так, как это работает по сей день в современном C, когда функция не имеет прототипа или когда используются вариационные параметры.

Теперь, cue в современном C, который имеет прототипы функций и использует синтаксис определения функции в современном стиле. Чтобы сохранить и воспроизвести "традиционные" функциональные возможности strchr, как описано выше, у нас нет другого выбора, кроме как объявить параметр strchr как int и явно преобразовать его в char внутри функции, Это именно то, что вы наблюдаете в коде, который вы указали. Это точно так же, как функциональные возможности strchr описаны в стандарте.

Кроме того, если у вас уже скомпилированная устаревшая библиотека, где strchr определяется в стиле K & R, как показано выше, и вы решили предоставить современные прототипы для этой библиотеки, правильное объявление для strchr будет

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

потому что int - это то, что ожидает предыдущая реализация, физически получаемая как c. Объявление его с параметром char будет неправильным.

По этой причине вы никогда не увидите "традиционные" стандартные библиотечные функции, ожидающие параметры типа char, short или float. Все эти функции будут объявлены с параметрами типа int или double.

В основе стандартной гарантии лежит то же самое, что указатели char и указатели void * имеют одинаковые требования к представлению и выравниванию. Опираясь на эту гарантию, вы можете объявить malloc как функцию void * -returning, а затем использовать это объявление с предварительно скомпилированной старой версией стандартной библиотеки, где malloc действительно возвращен char *.


Ссылка: логика C99, версия 5.10

7.1.4 Использование библиотечных функций
/-/
Все прототипы библиотек указаны в терминах "расширенных" типов: аргумент, ранее объявленный как char, теперь записывается как int. Эта гарантирует, что большинство функций библиотеки можно вызвать с помощью или без прототипа в объеме, что обеспечивает обратную совместимость с код pre-C89

Ответ 2

В c тип символьного литерала int. Например: 'a' имеет тип int.

Ответ 3

Я думаю, что это можно объяснить не чем иным, как случайностью истории. Вы совершенно правы, что char кажется очевидным типом данных для поиска персонажа.

В некоторых ситуациях в библиотеке C, например, функция getc(), возвращается символ int для символа, считываемого с ввода. Это не char, потому что может быть возвращено дополнительное несимвольное значение (EOF, обычно -1), чтобы указать конец символьного потока.

Случай EOF не применяется к функции strchr(), но они не могут вернуться назад и изменить объявление функции в библиотеке C. Теперь

Ответ 4

int c - это символ, который вы хотите найти. Символ передается как целое число, но на самом деле ищутся только младшие 8 бит. Поэтому он должен быть передан char

Функция strchr выглядит следующим образом:

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

Как вы видите, существует cast от int c до (char)c.

Теперь, чтобы ответить на ваш вопрос, ваш char ch преобразуется в целое число int c и применяется как порядковое значение символа.

Итак, следующая программа должна быть в порядке:

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

int main(void){
    char *name = "Michi";
    int c = 99; /* 99 is the ANSCI 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 ANSCI code of c*/

    char *ret = strchr(name, c);

    printf("String after %s\n", ret);
    return 0;
}

Из-за multi-character character constant, который overflow in implicit constant conversion