С++: можно ли присвоить int char*?

Я читаю главу 2 Advanced Linux Programming:
http://www.advancedlinuxprogramming.com/alp-folder/alp-ch02-writing-good-gnu-linux-software.pdf

В разделе 2.1.3 Using getopt_long есть пример программы, которая выглядит примерно так:

int main (int argc, char* argv[]) {
  int next_option;
  // ...
  do {
    next_option = getopt_long (argc, argv, short_options, long_options, NULL);
    switch (next_option) {
       case ‘h’: /* -h or --help */
       // ...
    }
    // ...

Мое внимание привлекло то, что next_option объявлен как int. Функция getopt_long(), по-видимому, возвращает целое число, представляющее короткий аргумент командной строки, который используется в следующем операторе switch. Как получилось, что целое число можно сравнить с символом в операторе switch?

Существует ли неявное преобразование из char (один символ?) в int? Насколько код выше действителен? (см. полный код в связанном pdf)


person augustin    schedule 29.08.2010    source источник
comment
Гм... Во-первых, вы говорите, что getopt_long() явно возвращает char*. Затем вы спрашиваете, существует ли неявное приведение типов char к int. Первая часть про char *, вторая про char. Где связь?   -  person AnT    schedule 29.08.2010
comment
@AndreyT: ты смотрел код, который я пытаюсь понять? next_option объявлен как int, но сравнивается с символом в статусе switch. Проверьте исходный код в pdf.   -  person augustin    schedule 29.08.2010
comment
Нет смысла продолжать, так как вы уже отредактировали вопрос, чтобы удалить часть, связанную с char *.   -  person AnT    schedule 29.08.2010
comment
@AndreyT Я все еще пытаюсь понять код в книге. Я все еще в замешательстве и хотел бы понять, почему код действителен.   -  person augustin    schedule 29.08.2010
comment
Я уже предоставил вам довольно исчерпывающее объяснение ниже.   -  person AnT    schedule 29.08.2010


Ответы (6)


Ни в C, ни в C++ нет типа, который может хранить «символы» как значения с некоторыми выделенными специфическими для символов свойствами. В этом смысле нет «символьного» типа ни в C, ни в C++.

В языках C++ и C char является интегральным типом. Он содержит числа. Это всего лишь наименьший (с точки зрения диапазона) интегральный тип. Преобразование между char и int существует точно так же, как между int и long или int и short. char не имеет особого статуса среди других интегральных типов (помимо того, что char тип отличается от signed char типа).

Литерал формы 'h' в C++ имеет тип char, но, как и любой другой целочисленный тип, он сравним с int. Вот почему вы можете использовать его в метке case так же, как в исходном примере.

Другими словами, ваш исходный код настолько же «странен», насколько

switch (next_option) {
       case 1L: ...
       // ...
    }

было бы. В этом случае аргумент switch — это int, а метка case — long. Код действителен. Вы находите это удивительным? Возможно нет. Ваш пример с 'h' мало чем отличается.

person AnT    schedule 29.08.2010
comment
Я действительно хочу, чтобы тег новичок был принят здесь. Да, я нахожу такие вещи удивительными. Я этого не ожидал. Вы предоставили несколько указателей на концепции, которые я мог бы искать и изучать больше. Мне нужно время, чтобы понять это. Спасибо. - person augustin; 29.08.2010
comment
char не имеет особого статуса среди других целочисленных типов. У него нет ловушек! :) - person GManNickG; 29.08.2010
comment
@GMan я считаю это немного полезным свойством :( Вы все еще не можете надежно использовать его для копирования произвольных байтов, потому что только для unsigned char гарантируется, что скопированные байты точно такие же (для char у вас может быть несколько представлений для одного и того же значения, например отрицательный и положительный 0). - person Johannes Schaub - litb; 29.08.2010

Вы ошибаетесь - getopt_long(3) возвращает целое число.

person Shaggy Frog    schedule 29.08.2010
comment
Так как же получилось, что это int можно сравнить с «h» или другими символами в операторе switch? - person augustin; 29.08.2010
comment
Спасибо за уведомление, но оно не отвечает на мой вопрос. Я отредактировал вопрос соответственно. - person augustin; 29.08.2010
comment
char не представляет собой ничего особенного, просто 1-байтовая переменная целочисленного типа. Если вы сравниваете char с int, это как если бы вы сравнивали два целых числа (так же, как int с long или long long). - person jkerian; 29.08.2010
comment
@jkerian Спасибо. Вы отвечаете более или менее на то, что я действительно пытался спросить. Я не знал, что ты можешь это сделать. - person augustin; 29.08.2010

Некоторые функции возвращают int в C и char в C++. Возвращение int, когда char имело бы больше смысла, — это просто старое культурное решение C. Кроме того, в некоторых случаях необходимо, чтобы функция могла возвращать часовые, такие как EOF.

person Max Lybbert    schedule 29.08.2010

Как говорит другой ответчик, вы задаете здесь неправильный вопрос. Но чтобы ответить на вопрос, который вы задали:

Неявное приведение типов char* к int недоступно. На машинах x86 как int, так и char* имеют длину 32 бита, поэтому явное приведение типов "безопасно":

int x = (int*) &someChar;

НО ОЧЕНЬ НЕ РЕКОМЕНДУЕМ!!!

На машинах x64 это не будет работать! int остается длиной 32 бита, но все указатели теперь имеют длину 64 бита... так что вы потеряете данные в процессе!

person Mahmoud Al-Qudsi    schedule 29.08.2010
comment
Итак, что вы думаете об образце кода из главы 2 Advanced Linux Programming? Как следует реорганизовать код, чтобы он был безопасным для моего 64-битного ЦП/ОС? - person augustin; 29.08.2010

Согласно справочной странице, getopt_long возвращает int. И да, есть неявное приведение от char к int; char — это всего лишь однобайтовое целочисленное значение.

Таким образом, в этом случае приведение происходит не при назначении next_option, а в операторе case, где у вас есть символьная константа, сравниваемая с int. Конечно, это предполагает, что вы скомпилируете это как C++. В C++ символьная константа имеет тип char, но в C она имеет тип int, так что если вы скомпилируете этот код как C, то преобразования типов вообще не будет.

(И в своем вопросе вы упоминаете char*, но вы, вероятно, имели в виду char; здесь не используются указатели.)

person mkarasek    schedule 29.08.2010

Думайте о char как о 8-битном int. Вы можете выполнять целочисленные операции над символами и даже объявлять их беззнаковыми. Вы не удивитесь, если сможете сравнить короткое и длинное. Почему сравнение char и int должно быть другим?

person dan_waterworth    schedule 29.08.2010
comment
Нет, не думайте об этом как о 8-битном int. Думайте об этом как о наименьшем целочисленном типе в C++, который может быть или не быть 8-битным и может быть или не быть подписанным или беззнаковым. - person GManNickG; 29.08.2010
comment
В C++ байт должен быть не менее 8 бит. Символ должен быть одним байтом. - person dan_waterworth; 29.08.2010
comment
Символ - это один байт, и да, он должен быть не менее 8 бит. Вы сказали, что это как 8 бит, что является плохой практикой. - person GManNickG; 30.08.2010