переменная короткого типа автоматически расширяется до целочисленного типа? - PullRequest
2 голосов
/ 05 декабря 2009

Я хочу напечатать значение b [FFFC], как показано ниже,

short var = 0xFFFC;
printf("%d\n", b[var]);

Но на самом деле он печатает значение b [FFFF FFFC].

Почему это происходит?

Мой компьютер работает под управлением Windows XP в 32-разрядной архитектуре.

Ответы [ 6 ]

7 голосов
/ 05 декабря 2009

short - подписанный тип. Это 16 бит на вашу реализацию. 0xFFFC представляет целочисленную константу 65 532, но при преобразовании в 16-битное значение со знаком это приводит к -4.

Итак, ваша строка short var = 0xFFFC; устанавливает переменную -4 (в вашей реализации).

0xFFFFFFFC - это 32-битное представление -4. Все, что происходит, это то, что ваше значение преобразуется из одного типа в больший тип, чтобы использовать его в качестве индекса массива. Он сохраняет свое значение, которое составляет -4.

Если вы действительно хотите получить доступ к 65,533-му элементу вашего массива, то вам следует:

  • используйте больший тип для var. int будет достаточно для 32-битной Windows, но в целом size_t - это тип без знака, который гарантированно достаточно большой для неотрицательных индексов массива.
  • используйте unsigned short, который просто дает вам достаточно места для этого примера, но пойдет не так, если вы хотите сделать еще 4 шага вперед.
1 голос
/ 05 декабря 2009

В качестве обновления доступных типов данных C, посмотрите здесь . Существует правило, которое касается использования C, некоторые типы данных переводятся в их интегральный тип, например

.
char ch = '2';
int j = ch + 1;

Теперь посмотрите на RHS (правая сторона) выражения и обратите внимание, что ch будет автоматически продвигаться как int , чтобы получить желаемые результаты на LHS (LHS) выражение. Каким будет значение j? Код ASCII для '2' равен 50 десятичному или шестнадцатеричному 0x32, добавьте к нему 1, и значение j будет равно 51 десятичному или шестнадцатеричному 0x33.

Важно понимать это правило, и это объясняет, почему тип данных будет «повышен» до другого типа данных.

Что такое b? То есть массив, который, как я полагаю, содержит 655532 правильных элементов?

В любом случае, используя спецификатор формата %d для типа int, значение, во-первых, повышается до int, во-вторых, и, во-вторых, индекс индекса имеет тип int, следовательно, использование short var поощряется и поскольку размер данных типа int равен 4 байта, он получил повышение, и, следовательно, вы видите оставшуюся часть значения 0xFFFF 0xFFFC.

Здесь используется приведение , чтобы сообщить компилятору приведение типа данных к другому, что объясняется в связи с ответом Грегори Пакоша выше.

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

1 голос
/ 05 декабря 2009

используйте % hx или% hd вместо этого, чтобы указать, что у вас есть короткая переменная, например:

  printf("short hex: %hx\n", var);     /* tell printf that var is short and print out as hex */

РЕДАКТИРОВАТЬ : Упс, я неправильно понял вопрос. Это не было о printf (), как я думал. Таким образом, этот ответ может быть немного ОТ.

Новое : поскольку вы используете var в качестве индекса для массива, вы должны объявить его как unsigned short (вместо short):

unsigned short var = 0xFFFC;
printf("%d\n", b[var]);

«Короткая переменная» может быть интерпретирована как отрицательное число.

Чтобы быть более точным:

Вы «недополучаете» диапазон отрицательных значений: значения в диапазоне от 0x0000 до 0x7FFF будут в порядке. Но значения от 0x8000 до 0xFFFF будут отрицательными.

Вот несколько примеров использования var в качестве индекса для массива b []:

short var=0x0000;; // leads to b[0]        => OK
short var=0x0001;  // leads to b[1]        => OK
short var=0x7FFF;  // leads to b[32767]    => OK
short var=0x8000;  // leads to b[-32768]   => Wrong
short var=0xFFFC;  // leads to b[-4]       => Wrong

short var=32767;   // leads to the same as b[0x7FFF]   => OK
short var=32768;   // compile warning or error => overflow into 32bit range
1 голос
/ 05 декабря 2009

В современных компиляторах мы не можем использовать short (16 бит), если при записи short используется 32 бит.
например, я скомпилировал тот же код с gcc4 в Ubuntu Linux 32 bit:

int main(int argc, char** argv)
{
    short var = 0xFFFC;
    printf("%x\n", var);
    printf("%d\n", var);
    return (EXIT_SUCCESS);
}

и вывод:

fffffffc
-4

вы можете видеть приведение к 32-битному нормальному и использовать расширение знака в дополнении 2

0 голосов
/ 06 декабря 2009

В теме вашего вопроса вы уже догадались, что здесь происходит: да, значение типа short «автоматически расширяется» до значения типа int. Этот процесс называется интегральное продвижение . Вот как это всегда работает на языке Си: каждый раз, когда вы используете целочисленное значение, меньшее int, это значение всегда неявно повышается до значения типа int (беззнаковые значения могут повышаться до unsigned int). Само значение не меняется, конечно, только тип значения изменяется. В приведенном выше примере 16-разрядное значение short, представленное шаблоном 0xFFFC, совпадает с 32-разрядным значением int, представленным шаблоном 0xFFFFFFFC, что составляет -4 в десятичных числах. Кстати, остальная часть вашего вопроса звучит довольно странно: продвижение или нет, ваш код пытается получить доступ к b[-4]. Повышение до int ничего не меняет.

0 голосов
/ 05 декабря 2009

Вы ожидали просто сохранить 16-битную переменную в 32-битной памяти ... вы видите, что каждый адрес памяти содержит целое 32-битное слово (аппаратное обеспечение).

Дополнительный FFFF происходит из-за того, что short - это значение подписано , а когда присвоено int (при вызове printf), оно получает расширение со знаком. При расширении двух дополнений с 16 до 32 бит расширение выполняется путем репликации последнего N бита на все остальные M-N слева. Конечно, вы этого не хотели.

Итак, в этом случае вас интересуют абсолютные позиции массива, поэтому вы должны объявить свой индексатор как unsigned .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...