2013-12-25 6 views
1

Я пытаюсь преобразовать строку, представляющую 24-разрядное шестнадцатеричное число (FFFFFF), в десятичный эквивалент (-1). Может ли кто-нибудь помочь мне понять, почему следующий код не возвращает -1?Преобразование FFFFFF в десятичное значение (язык C)

Спасибо, LC

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main(void) { 
char temp_str[] = "FFFFFF"; 
long value; 
value = strtol(temp_str, NULL, 16); 
printf("value is %ld\n", value); 
} 
+3

Он преобразует 'FFFFFF' в' 16777215', что является правильным. В чем проблема? – haccks

+0

Почему sould '0xffffff' эквивалентно' -1' конвертирует, по крайней мере, в 32 бита? – alk

ответ

3

Похоже, ваш вклад является 24-бит 2 дополнением представление числа, но strtol не обрабатывает отрицательные числа таким образом (и даже если это так, то есть никак не зная, что вы имели в виду 24-битное представление). Он определяет только знак его выхода, основанный на существовании знака -.

Вы можете изменить свой код, чтобы получить результат, который вы хотите, добавив это после strtol:

if (value > 0x7fffff) 
    value -= 0x1000000; 

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

+0

Я не знаю, что ваше решение верное или нет, но 'value = (значение << 8) >> 8' проще понять –

+3

@ LưuVĩnhPhúc Мое решение является портативным, в то время как ваш будет работать только с 32-битными' long 'и даже то это вызовет неопределенное поведение. – interjay

+0

Решение для взлома хакера: 'value = (value^0x800000) - 0x800000;' который переносится и лучше подходит для конвейерной обработки. В моем ответе также вычитается 0x800000, а не 0x1000000. .. – nonsensickle

0

Не думайте, как компьютер сейчас, просто convery (FFFFFF) 16 до десятичного использования, используя обычное математическое мышление. Речь идет не о отрицательных обозначениях двух дополнений.

0

Поскольку вы запускаете эту программу на 32- или 64-разрядной машине, а не 24-битной. 0xffffff фактически равен 0x00ffffff, что равно 16777215 в десятичном значении.

Hex-представление -1 равно 0xffffffff или 0xffffffffffffffff.

+0

На самом деле это не так. проблема. Даже если вы запустили ее с помощью '' FFFFFFFF'' на 32-битной машине, она не вернет -1, а 'LONG_MAX'. – interjay

+0

Ну, он всегда может использовать strtoul() и конвертировать unsigned long to long. – blaze

+0

Примечание. Это не размер 'int' (32- или 64-разрядная машина), а' long'. Типичная 16-разрядная машина будет использовать 32-битную длину и иметь аналогичные проблемы. – chux

2

Взгляд хакера охватывает это под sign extension.

Для вашего 24-битного номера знак бит - это 24-й бит справа, и если он был установлен, шестнадцатеричное значение будет 0x800000.

Книга предлагает следующие:

((x + 0x800000) & 0xFFFFFF) - 0x800000 

or 

((x & 0xFFFFFF) xor 0x800000) - 0x800000 

Из вашего вопроса я хотел бы сказать, что ваш номер никогда не будет больше, чем 24 бита, поэтому я хотел бы использовать второй вариант в коде следующим образом:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main(void) { 
    char temp_str[] = "FFFFFF"; 
    long value; 
    value = strtol(temp_str, NULL, 16); 
    value = (value^0x800000) - 0x800000; // Notice that I'm not using the & 0xFFFFFF since I assumed that the number won't have more than 24 bits. 
    printf("value is %ld\n", value); 
} 

Edit 1:

Я боюсь, что мой первоначальный ответ, хотя с технической точки зрения не ответить на поставленный questi на.

Может ли кто-нибудь помочь мне понять, почему следующий код не возвращает -1?

Другие уже рассмотрели это к моменту, когда я ответил, но я все равно его повторю.

Ваша строка "FFFFFF", она состоит из шести шестнадцатеричных цифр. Каждая шестнадцатеричная цифра представляет 4 бита, поэтому ваша строка представляет 24-битное число.

Ваша переменная long value имеет длину , которая обычно соответствует ширине слова вашего процессора (32 бит или 64 бит).Поскольку в эти дни long может быть 32 бита или 64 бита в зависимости от вашей архитектуры, вам не гарантируется получение -1, если вы не дадите точно нулевое количество шестнадцатеричных цифр.

Если long на вашей машине составляет 32 бита, то две вещи истинны:

  1. sizeof(long) возвратит
  2. Использование "FFFFFFFF" вернет -1

Если long на ваш компьютер 64 биты, то возможны две вещи:

    444 +42760359211350144688888 sizeof(long) вернется 8
  1. Использование "FFFFFFFFFFFFFFFF" вернет -1

Отступление

Это затем привело меня совершенно другой путь. Мы можем обобщить это и создать программу, которая строит строку для вашей машины, так что она всегда будет возвращать -1 из строки.

#include #include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main(void) { 
    const char* ff = "FF"; 
    char temp[sizeof(long) * 2 + 1]; // Ensure that the string can store enough hex digits so that we can populate the entire width of long. Include 1 byte for '\0' 
    int i; 
    long value; 

    /* Fill the temp array with FF */ 
    for (i = 0; i < sizeof(long); ++i) 
    { 
     strcpy(&temp[i * 2], ff); 
    } 

    value = strtol(temp, NULL, 16); 
    printf("value of %s is %ld\n", temp, value); 
} 

Это плохой способ получить -1 результат, так как опция не является просто использовать

long value = -1; 

, но я буду считать, что это просто академическое упражнение.

Смежные вопросы