Конвертировать char в int в C и C ++

401

Как преобразовать charв intв C и C ++?

mainajaved
источник
1
@Matt: было бы неплохо быть более конкретным. вопрос об обобщении просто предлагает обобщенные ответы, которые не применимы или даже не подходят для вашей задачи. имейте в виду, что когда вам приходится спрашивать, вы, вероятно, не знаете достаточно, чтобы правильно обобщать.
ура и hth. - Альф
@Alf P. Steinbach: первоначальный вопрос был неопределенным в отношении того, на каком языке. С ключевыми словами cи c++, я думаю, ответы на оба языка являются разумными.
Мэтт Джоунер
8
Исходя из моего большого опыта работы на других технических форумах, моя интуиция заключается в том, что ОП на самом деле означает «как взять текстовое представление числа (в базе 10) и преобразовать его в соответствующее число?» Вообще говоря, неофиты C и C ++ обычно имеют невероятно смутные представления о том, как работает текст на этих языках и что на charсамом деле означает.
Карл Кнехтель
3
@KarlKnechtel: Если это правда (я даю около 50/50, так как многие ранние учебники также поощряют получение значений ASCII из символов, даже если ASCII не охватывает весь диапазон), ОП требует ясности - но это обман of stackoverflow.com/questions/439573/… .
Фред Нурк
3
У ОП было три часа, чтобы уточнить этот вопрос, и он не смог этого сделать. Как это, нет никакого способа узнать, что на самом деле спрашивают. Проголосовал за закрытие.
sbi

Ответы:

552

Зависит от того, что вы хотите сделать:

чтобы прочитать значение в виде кода ASCII, вы можете написать

char a = 'a';
int ia = (int)a; 
/* note that the int cast is not necessary -- int ia = a would suffice */

для преобразования символов '0' -> 0, '1' -> 1и т.д., вы можете написать

char a = '4';
int ia = a - '0';
/* check here if ia is bounded by 0 and 9 */

Пояснение :
a - '0'эквивалентно ((int)a) - ((int)'0'), что означает, что значения ascii символов вычитаются друг из друга. Поскольку 0непосредственно 1в таблице ascii (и так далее, до тех пор 9, пока не будет ), различие между ними дает число, которое aпредставляет символ .

Фу Бах
источник
14
ia = (a - '0')% 48;
Кшитий Банерджи
@KshitijBanerjee Это не очень хорошая идея по двум причинам: он дает вам отрицательное число для символов ascii перед '0' (например, &-> -10), и это дает вам числа больше 10 (как x-> 26)
SheetJS
2
int ia = a - '0' - это то, что вам нужно
фанк
5
@ kevin001 Если вы хотите преобразовать char в int, а символ '1'предоставляет число ascii, которого нет 1, вам нужно удалить смещение, '0'чтобы выровнять его, чтобы считать от 0 до 9. Последовательные числа 1-9 соседствуют в целом числе ascii.
krisdestruction
В ролях не требуется / не желательно
Крейг Эстей,
97

Ну, в коде ASCII числа (цифры) начинаются с 48 . Все, что вам нужно сделать, это:

int x = (int)character - 48;
Влад Изок
источник
19
@chad: не только более читабельный, но и более портативный. C и C ++ не гарантируют представление ASCII, но они гарантируют, что независимо от того, какое представление используется, представления 10 десятичных цифр являются смежными и в числовом порядке.
Бен Фойгт
Единственное, что я бы изменил, - это повернул 48, что кажется немного «волшебным» для'0'
ArielGro
59

C и C ++ всегда продвигают типы по крайней мере int. Кроме того, символьные литералы имеют тип intв C и charв C ++.

Вы можете преобразовать charтип, просто присвоив int.

char c = 'a'; // narrowing on C
int a = c;
Мэтт Джойнер
источник
3
Вы также можете использовать очень недооцененный унарный operator+() для этой цели.
Cubbi
24
-1 Ответ неверен только для осмысленного толкования вопроса. Это (код int a = c;) будет хранить любые отрицательные значения, с которыми стандартные функции библиотеки C не могут иметь дело. Стандартные библиотечные функции C устанавливают стандарт того, что значит обрабатывать charзначения как int.
ура и hth. - Альф
6
@Matt: я держу вниз голосов. Я бы усилил это, если это возможно! Интерпретация вопроса, которую вы и другие предположили, не имеет смысла, потому что она слишком тривиальна, и потому что для конкретной комбинации типов OP существует не так уж и тривиальная очень важная практическая проблема. Совет, который вы даете, напрямую опасен для новичка. Скорее всего, это приведет к неопределенному поведению для их программ, которые используют функции классификации символов стандартной библиотеки C. Реф. на ответ @ Sayam он удалил этот ответ.
ура и hth. - Альф
3
-1 за неправильность: isupper () будет иметь неопределенные результаты, если передан 1252 старшего символа.
Крис Бекке
1
Что вы подразумеваете под «всегда продвигать»? Значения продвигаются во время неявных преобразований, передачи определенных типов параметров (например, в функцию varargs) и когда оператор должен сделать свои операнды совместимыми типами. Но, безусловно, бывают случаи, когда значение не продвигается (например, если я передаю символ функции, ожидающей символ), иначе у нас не было бы типов, меньших, чем int.
Адриан Маккарти
31

char - это всего лишь 1-байтовое целое число. В типе char нет ничего волшебного! Точно так же, как вы можете назначить short для int или int для long, вы можете назначить char для int.

Да, имя типа данных примитива бывает «char», что означает, что он должен содержать только символы. Но на самом деле «char» - это просто плохое имя, которое может сбить с толку всех, кто пытается выучить язык. Лучшее имя для него - int8_t, и вы можете использовать это имя, если ваш компилятор следует последнему стандарту Си.

Хотя, конечно, вы должны использовать тип char при обработке строк, потому что индекс классической таблицы ASCII умещается в 1 байт. Тем не менее, вы могли бы также выполнять обработку строк с помощью обычных целочисленных значений, хотя в реальном мире нет практической причины, по которой вы захотите это сделать. Например, следующий код будет отлично работать:

  int str[] = {'h', 'e', 'l', 'l', 'o', '\0' };

  for(i=0; i<6; i++)
  {
    printf("%c", str[i]);
  }

Вы должны понимать, что символы и строки - это просто числа, как и все остальное в компьютере. Когда вы пишете «а» в исходном коде, он предварительно обрабатывается до числа 97, которое является целочисленной константой.

Так что если вы напишите выражение, как

char ch = '5';
ch = ch - '0';

это на самом деле эквивалентно

char ch = (int)53;
ch = ch - (int)48;

который затем проходит через целочисленные продвижения языка C

ch = (int)ch - (int)48;

а затем обрезается до символа, чтобы соответствовать типу результата

ch = (char)( (int)ch - (int)48 );

Между строк происходит много таких тонких вещей, когда char неявно рассматривается как int.

Лундин
источник
Поскольку вопрос не помечен ascii, вы не должны предполагать какую-либо конкретную кодировку. Установка charравным int8_tявляется неправильным, потому что это может быть равно uint8_tили uint24_t.
Роланд Иллиг
1
@RolandIllig Нет, a charвсегда равен 1 байту, и если типы int8_t/ uint8_tсуществуют в данной системе (что весьма вероятно), они смогут соответствовать результату a char, поскольку тогда он будет равен 8 битам. В очень экзотических системах, таких как различные устаревшие DSP, charбудет 16 бит, и их uint8_tне будет. Написание кода для совместимости с устаревшими DSP не имеет смысла, так же как написание для совместимости с системами дополнения или знака и величины. Огромная трата времени, поскольку такие системы практически не существуют в реальном мире.
Лундин
18

(Этот ответ касается стороны C ++, но проблема расширения знака существует и в C).

Обработка всех трех charтипов ( signed,, unsignedи char) более сложна, чем кажется на первый взгляд. Значения в диапазоне от 0 до SCHAR_MAX(что составляет 127 для 8-разрядного char) просты:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
int n = c;

Но когда somevalueвыход за пределы этого диапазона, только прохождение unsigned charдает вам согласованные результаты для «одинаковых» charзначений во всех трех типах:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
// Might not be true: int(c) == int(sc) and int(c) == int(uc).
int nc = (unsigned char)c;
int nsc = (unsigned char)sc;
int nuc = (unsigned char)uc;
// Always true: nc == nsc and nc == nuc.

Это важно при использовании функций из ctype.h , таких как isupperor toupper, из-за расширения знака:

char c = negative_char;  // Assuming CHAR_MIN < 0.
int n = c;
bool b = isupper(n);  // Undefined behavior.

Обратите внимание, что преобразование через int неявное; это тот же UB:

char c = negative_char;
bool b = isupper(c);

Чтобы исправить это, пройти через unsigned char, который легко сделать обертывание ctype.h функций через safe_ctype :

template<int (&F)(int)>
int safe_ctype(unsigned char c) { return F(c); }

//...
char c = CHAR_MIN;
bool b = safe_ctype<isupper>(c);  // No UB.

std::string s = "value that may contain negative chars; e.g. user input";
std::transform(s.begin(), s.end(), s.begin(), &safe_ctype<toupper>);
// Must wrap toupper to eliminate UB in this case, you can't cast
// to unsigned char because the function is called inside transform.

Это работает, потому что любая функция, принимающая любой из трех типов символов, может также принимать другие два типа символов. Это приводит к двум функциям, которые могут обрабатывать любые типы:

int ord(char c) { return (unsigned char)c; }
char chr(int n) {
  assert(0 <= n);  // Or other error-/sanity-checking.
  assert(n <= UCHAR_MAX);
  return (unsigned char)n;
}

// Ord and chr are named to match similar functions in other languages
// and libraries.

ord(c)всегда дает вам неотрицательное значение - даже если передано отрицательное charили отрицательное signed char- и chrпринимает любое значение, ordпроизводит и возвращает точно то же самое char.

На практике я, вероятно, просто использовал бы приведение unsigned charвместо того, чтобы использовать их, но они кратко оборачивают приведение, предоставляют удобное место для добавления проверки ошибок для int-to- char, и были бы короче и понятнее, когда вам нужно использовать их несколько раз. в непосредственной близости.

Фред Нурк
источник
7

Это зависит от того, что вы подразумеваете под «конвертировать».

Если у вас есть серия символов, представляющих целое число, например «123456», то в C есть два типичных способа сделать это: использовать специальное преобразование, такое как atoi () или strtol () , или универсальный sscanf. () . C ++ (который на самом деле является другим языком, маскирующимся под обновление) добавляет третий, stringstream.

Если вы имеете в виду, что хотите, чтобы точный битовый шаблон в одной из ваших intпеременных рассматривался как a char, это проще. В C разные целочисленные типы действительно больше относятся к состоянию ума, чем к отдельным отдельным «типам». Просто начните использовать его там, где вас charпросят, и вы должны быть в порядке. Возможно, вам понадобится явное преобразование, чтобы компилятор прекратил ныть, но все, что нужно сделать, это отбросить все лишние биты после 256.

ТЕД
источник
6

У меня есть абсолютно nullнавыки в C, но для простого разбора:

char* something = "123456";

int number = parseInt(something);

... это сработало для меня:

int parseInt(char* chars)
{
    int sum = 0;
    int len = strlen(chars);
    for (int x = 0; x < len; x++)
    {
        int n = chars[len - (x + 1)] - '0';
        sum = sum + powInt(n, x);
    }
    return sum;
}

int powInt(int x, int y)
{
    for (int i = 0; i < y; i++)
    {
        x *= 10;
    }
    return x;
}
Хенке
источник
Этот код быстро вызывает неопределенное поведение и поэтому не подходит для копирования и вставки. (переполнение)
Роланд Иллиг,
4

Предположительно, вы хотите это преобразование для использования функций из стандартной библиотеки C.

В этом случае do (синтаксис C ++)

typedef unsigned char UChar;

char myCppFunc( char c )
{
    return char( someCFunc( UChar( c ) ) );
}

Выражение UChar( c )конвертируется unsigned charв, чтобы избавиться от отрицательных значений, которые, кроме EOF, не поддерживаются функциями C.

Затем результат этого выражения используется в качестве фактического аргумента для intформального аргумента. Где вы получаете автоматическое продвижение в int. В качестве альтернативы вы можете написать этот последний шаг явно, например int( UChar( c ) ), но лично я нахожу это слишком многословным.

Ура & hth.,

Ура и hth. Альф
источник
0

У меня были проблемы с преобразованием массива типа char "7c7c7d7d7d7d7c7c7c7d7d7d7d7c7c7c7c7c7c7d7d7c7c7c7c7d7c7d7d7d7c7c2e2e2e"в его действительное целочисленное значение, которое могло бы быть представлено 7C как одно шестнадцатеричное значение. Итак, после поиска помощи я создал это и подумал, что было бы здорово поделиться.

Это разделяет строку char на правильные целые числа и может быть полезна большему количеству людей, чем только я;)

unsigned int* char2int(char *a, int len)
{
    int i,u;
    unsigned int *val = malloc(len*sizeof(unsigned long));

    for(i=0,u=0;i<len;i++){
        if(i%2==0){
            if(a[i] <= 57)
                val[u] = (a[i]-50)<<4;
            else
                val[u] = (a[i]-55)<<4;
        }
        else{
            if(a[i] <= 57)
                val[u] += (a[i]-50);
            else
                val[u] += (a[i]-55);
            u++;
        }
    }
    return val;
}

Надеюсь, поможет!

Mathorlaz
источник
Вы когда-нибудь тестировали этот код? 50 должно быть 48, 55 работает только для прописных букв ASCII, в то время как ваш пример содержит строчные буквы.
Роланд Иллиг
0

Для char или short для int вам просто нужно присвоить значение.

char ch = 16;
int in = ch;

То же самое для int64.

long long lo = ch;

Все значения будут 16.

Riwels
источник
-1
int charToint(char a){
char *p = &a;
int k = atoi(p);
return k;
}

Вы можете использовать этот метод atoi для преобразования char в int. Для получения дополнительной информации вы можете обратиться к этому http://www.cplusplus.com/reference/cstdlib/atoi/ , http://www.cplusplus.com/reference/string/stoi/ .

пранав суреш
источник
1
Это неопределенное поведение. Взятие адреса переменной char даст вам char *, но не C-строку, чего ожидает atoi.
luizfls