Не могу сказать, что плохо знаю C / C ++, но столкнулся с интересным синтаксисом.
У меня есть этот код:
int i=7;
char* m=(char*)&i;
m[2]=9;
cout<<i;
Его вывод 589831. Так может кто-нибудь подробно объяснить мне, что здесь происходит.
Целое число i
очень вероятно, занимает 4 байта, расположенных с самым низким значением первым (little-endian). В памяти значения выглядят так:
0x07 0x00 0x00 0x00
Вы изменили значение в индексе 2, теперь оно выглядит так:
0x07 0x00 0x09 0x00
Если вы перевернете байты и соедините их вместе, они получат шестнадцатеричное значение 0x00090007, которое равно 589831 в десятичном виде.
{ 07, 00, 00, 00 }
{ 07, 00, 09, 00 }
Короче говоря, это пример того, как вы можете манипулировать отдельными байтами в многобайтовом целом числе.
Вы приводите целочисленный адрес к char*
затем изменив его с помощью записи массива. Этот шаг
m[2] = 9;
такой же, как арифметика указателя
*(m+2) = 9;
то есть, это изменение байта по адресу m
+ 2 байта. Таким образом, вы изменили один из байтов (3-й) в вашем начальном целочисленном значении
Вот мое объяснение происходящего, затем объяснение.
// An integer on the stack, probably 4 bytes big, but we can't say that for sure.
int i=7; // Looks like 0x0000007 in memory. Endianness needs to be considered.
// Treat that integer as a \0 terminated string.
char* m=(char*)&i; // Acts as an empty string since the first byte is a 0, but we can't count on that.
// Set the second byte to 9.
m[2]=9; // Results in i being 0x00090007 (589831 decimal) on whatever architecture you are running. Once again, can't count on it.
// Print the modified integer.
cout<<i;
Это невероятно опасная и глупая вещь по трем причинам …
Вы не должны рассчитывать на порядок байт вашей архитектуры. Ваш код может в конечном итоге работать на процессоре, который имеет другое представление о том, что int
является.
Вы не можете рассчитывать на int
всегда быть 4 байта.
Теперь у вас есть char*
что если вы когда-нибудь будете выполнять строковую операцию, это может привести к сбою. В вашем конкретном случае он напечатает пустую строку, но это не займет много времени, чтобы это целое число не содержало 0 байт и продолжало читать другие части вашего стека.
если ты действительно очень необходимо сделать это, предпочтительный метод заключается в использовании союзы но этот вид небольшого изменения очень склонен к ошибкам, и профсоюзы делают очень мало, чтобы помочь.
int i=7
резервирует 4 байта памяти для целых чисел и в зависимости от архитектуры процессора (допустим, у вас i86) будет производить что-то подобное в памяти
7 0 0 0
затем указатель m создан, чтобы указывать на начало 7 0 0 0
,
после m[2] = 9
память должна выглядеть
7 0 9 0
(массивы начинаются с нуля);
тогда вы распечатываете я