Явные проблемы приведения, C - PullRequest
3 голосов
/ 05 декабря 2011

У меня есть инструкция case в C:

case GOTO: {
    int o1 = (int)P[pc+1];
    unsigned int o2 = (unsigned)P[pc+2];
    int offset =(o1<<8) | o2;
    pc = pc + (int)offset;
    break;
}

Теперь о коде: P[pc+x] даст 1 байтовое целое число.И, в конце концов, я хочу установить pc в 4 байт int со знаком.Однако это не так.То, что он делает, это берет байт 1, сдвигая его, затем беря второй байт и затем побитовый или, и просто добавляя его.Это не принимая во внимание знак o1.Итак, если P[pc+1] = FF и P[pc+2] = E1, то происходит offset = 0000FFE1.Однако я хочу offset = FFFFFFE1.По сути, первые 2 байтов должны принимать знак P[pc+1].Но этого не происходит.Что я делаю не так?

Ответы [ 3 ]

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

Проверьте это, если это имеет смысл для вас: #include

int main(void) {
  short pc1= 0xFF;
  short pc2= 0xE1;
  int pc = 0;

  unsigned int highbits = 0xFFFFFFFF;

  // Check for sign bit, if true OR with highbits
  // to set all remaining bits to high
  int o1 = pc1 & 0xF0 ? pc1 | highbits : pc1;
  int offset = (int)( (o1<<8) | pc2 );
  pc = pc + (int)offset;
  printf("\npc1=%x pc2=%x pc=%x", pc1, pc2, pc);
  printf("\n");

  return 0;
}

ВЫВОД:

pc1=ff pc2=e1 pc=ffffffe1
1 голос
/ 05 декабря 2011

Я не видел объявления P, но когда вы говорите, что это байтовый массив, я предполагаю, что конкретный тип - беззнаковый символ.

Если бы оно было подписано, приведение могло бы вести себя так, как вы хотели, потому что, например, символ -1 стал бы -1 int, бит знака сдвигался, а остальные биты инвертировались, как требовалось. Но когда вы преобразуете неподписанный символ в подписанный int, результат всегда будет положительным.

Итак, чтобы решить проблему, один из способов - привести указатель / массив перед разыменованием, и он даст желаемый результат:

int o1 = (int)(((char *)P)[pc+1]);

Еще одна вещь: сдвиг бита не будет хорошо работать со знаковыми значениями, потому что он просто сместит знаковый бит. Это будет работать в вашем примере, потому что у вас есть 0xFF, но если бы у вас было 0x80, это было бы 0x80000000 как int, и стало бы 0x00000000 после сдвига.

Итак, вместо 8-битного сдвига, сделайте умножение:

int offset =(int)( (o1 * 256) + o2 );
0 голосов
/ 05 декабря 2011

Вы должны проверить, как ваш компилятор выполняет приведение без знака и наоборот в C. Если я правильно помню (извините, если я неправ), если у вас есть хотя бы одна переменная UNSIGNED в такой операции, как A = B (где A получаетзначение B), компилятор будет обрабатывать оба значения как значения UNSIGNED.

Возможно, это портит ваш код.Дайте мне знать ответ так или иначе, я прокомментирую здесь, если я выясню, почему это происходит

...