Какова роль x = (char *) & a и что она делает? - PullRequest
0 голосов
/ 31 октября 2018

У меня есть этот кусок кода:

int a;
char *x;
x = (char *) &a;
a = 512;
x[0] = 1;
x[1] = 2;
printf("%d\n");
return 0;

Это печатает 513 . Пожалуйста, объясните и особенно строку 3.

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Пока int больше, чем char на конкретной машине (и по стандарту C это должно быть), ваш побайтный доступ сам по себе не является неопределенным. Endianess может быть определен. Размеры шрифтов можно определить с помощью sizeof.

То, что вы действительно здесь делаете, это задаете конкретные байты (x в вашем коде - это указатель на символ; нотация массива [] позволяет вам получить доступ к отдельным байтам в вашем целом числе) вашего целочисленного значения для некоторых битовых комбинаций. Порядок в вашей машине будет определять, что представляют эти битовые комбинации, если вы снова получите доступ к измененным таким образом байтам как целое число.

Пока вы не пишете в байт, который не является частью исходного целого числа, код не является неправильным, за исключением отсутствующего аргумента в вызове printf, который действительно является UB.

Вопрос, который остается, состоит в том, какой цели могут служить такие манипуляции. Но есть способы использовать эту технику.

0 голосов
/ 19 июля 2019

Предположим, вы находитесь на машине, где у int 4 байта. 512 в шестнадцатеричном формате будет «00 00 02 00». На процессоре с прямым порядком байтов указатель указывает на младший значащий байт. Чтобы установить каждый байт индивидуально, указатель на int приводится к указателю на char: x = (char *) & a; как символ всегда кодируется одним байтом. Теперь четыре байта обрабатываются как массив из четырех байтов. Младший значащий байт устанавливается в «1» с помощью x [0] = 1; Следующий байт имеет значение «2» (так или иначе, поэтому строка x [1] = 2; может быть пропущена), а байты 3 и 4 нетронуты 00 и 00. «a» теперь «00 00 02 01» или 513. Конечно, в выражении printf отсутствует «a»: printf («% d \ n», a);

0 голосов
/ 31 октября 2018

Строка 3 просто указывает x на адрес a. Как специальное правило в C, нам разрешено использовать символьные указатели специально для доступа к отдельным байтам любой другой переменной.

Дальнейший доступ к x изменит отдельные байты a, таким образом, что это зависит от состояния процессора. На машине с прямым порядком байтов 512 = 0x200, где два младших байта имеют значения 0x00 и 0x02 соответственно. x[0] = 1; изменяет младший байт на 0x01, а x[1] = 2; записывает значение 0x02 в байт, который уже содержал 0x02. Результат будет 0x201 = 513 десятичных.

Проблема здесь в том, что printf("%d\n"); вызывает неопределенное поведение, поскольку содержит неверное количество параметров.

Краткое содержание: код - бред, и язык Си не определяет, что будет делать эта программа. Может произойти сбой, распечатать любое значение или напечатать вообще никакого значения. Размышление о том, почему оно ведет себя определенным образом, не имеет смысла. Вместо этого сосредоточьтесь на изучении того, как избежать неопределенных ошибок в поведении.

...