2015-01-30 4 views
2

Есть ли способ доступа к некоторым частям шестнадцатеричного числа в C?Побитовые операции с шестнадцатеричными номерами

Я хочу написать функцию, которая принимает шестнадцатеричное число и отменяет его, но оставляет младший значащий байт без изменений. Пример: 0x87654321 должен стать 0x789ABC21.

Я попытался каким-то образом сохранить LSB, а затем применить его к отрицаемому x, но моя проблема в том, что моя маска применяется ко всем байтам. Я мог бы жестко запрограммировать его для определенного значения, но, очевидно, это не то, что я хочу.

void b(int x) { 
    int temp = x & 0xFF; // temp is all 0 with the LSB being the same as x's 
    x = ~x; // this negates x 
    // one of a couple of attempts I tried thus far: 
    // x = (x & 0x00) | temp; 
    // idea: change x's LSB to 00 and OR it with temp, 
    // changing x's LSB to temp's LSB 
} 

Я был бы признателен, если вы не размещаете код для решения, а просто ответить, есть ли способ применить битовые операции к конкретным разделам шестнадцатеричного числа, или, как я мог бы решить эту проблему ,

+0

Я не совсем знаком с C, и что именно делает &&? В Java или C++ это было бы логичным сравнением, но здесь это не имеет особого смысла, не так ли? – Beko

+1

'x = (~ x & ~ 0xFF) | (x & 0xFF); ' –

+0

Хотя я бы оценил ориентированный ответ, а не какой-то код, я все равно ценю это. Спасибо Ли, это действительно работает. – Beko

ответ

3

В целом вы можете работать с определенными битами значения с помощью маски .

Маска - это бит-шаблон с 1-м, где вы хотите работать, и 0s, где нет.

Кажется, вам нужны 3 операции: извлечение младшего байта, отрицание, восстановление младшего байта. Вы можете понять отрицание, поэтому я просто расскажу об извлечении битового поля и восстановлении извлеченного битового поля.

Чтобы извлечь определенные биты, используйте маску с 1s для желаемых бит и используйте поразрядные и оператор &. Операторы и устанавливают 0s для всех 0s маски и где маска равна 1, она копирует бит из другого аргумента. Если вам нужно изучить это значение в другом месте вашей программы, также может быть удобно сдвинуть вправо >> значение до нижней позиции (так что легче искать в таблицах).

Чтобы восстановить сохраненные бит, сдвиньте назад, если вы перенесли его ранее. Затем очистите эти биты от значения и используйте включительно - или| как поразрядную сумму всех одного бита. Чтобы очистить биты от значения, используйте инверсию маски из первой операции. То есть. y = x & 0xf экономит кусок, x & ~0xf очищает этот грызть, (x & ~0xf) | y рекомбинирует к тому же оригиналу x.

Edit: Если часть вы извлекая не в самом нижнем положении, скажем, второй байт (LSB) от 32 битового целого числа без знака, то это может быть полезно, чтобы переместить извлеченный значение нуля чтобы работать с ним.

x = 0x12345678; 
y = x & 0xFF00; // == 0x5600 
y >>= 8;   // == 0x56 

Но если вы сделаете это, то вы должны переместить его обратно в правильное положение (разумеется) перед обновлением большего значения с новым значением для битового поля.

x = (x & ~0xFF00) | (y << 8); 
+0

Я знаю об этом, но, как я уже сказал, моя маска применяется ко всем битам. – Beko

+0

Маска - это инструмент для выбора того, к каким битам применяется, путем управления таблицами истинности для двоичной операции. –

+0

Хорошо. Я сделал это с вашим подходом - ну, в основном я сделал то же, что и Ли Дэниел Крокер уже предложил. Хотя я не совсем понял часть с правой сменой. Не могли бы вы рассказать об этом или дать небольшой пример? – Beko

2

Если я правильно понял вопрос, похоже, что это будет что-то вроде этого (непроверено).

void b(int x) { 
    return (~x & ~0xFF) | (x & 0xFF); 
} 
+0

Он сказал, что LS * byte *, not * bit *, и ваш код зависит от 32-битных ints, поэтому ваши константы должны быть '~ 0xFF' и' 0xFF'. –

+0

@LeeDanielCrocker: Пропустил, что это был байт, а не бит. Обновлено. –

+0

Данг, потратил мое время, следуя указаниям: «Буду признателен, если вы не внесете код для решения» –

0

Я нашел способ манипулировать выбранным байтом. (!!! Это было бы домашнее задание 2.60 из CS: APP !!!)

Если 0x12345678 заданная шестнадцатеричное значение типа, скажем, INT, то делает это позволит мне изменить г-й байт:

int x = 0x12345678; 
unsigned char* xptr = (unsigned char*) &x; 
xptr[i] = 0; // say i=2, then this would yield: 0x120045678 

Теперь, если я хочу, чтобы добавить значение в позиции байт i, скажем, 0xAB, я бы сделал то, что уже упоминал luser droog:

int temp = 0xAB; 
temp = temp << i*8; // say i=2, then this would yield: 0x00AB0000 
x = x | temp; // this yields the desired result 0x12AB3456