Затык с преобразованием типов
От: TheMaster  
Дата: 07.04.15 04:56
Оценка: -1 :)
Сразу прошу прощения за форматирование: в предпросмотре всё почему-то выровнялось по центру, и я не нашёл кнопки, которая сделает привычное выравнивание по левому краю
Есть у меня буфер с байтами. Вот такой:
char buf[BUF_SIZE];        // Тут идут байты: 0xAA, 0xBB, 0xCC...

А надо — сделать текстовый файл (для одной вредной приблуды):
AA (0D, 0A — два символа перевода строки)
BB
CC
и так далее.

На первый взгляд, одно в другое преобразуется простейшей программой на чистом С (под рукой был только он):
#define DSK_BUF_SIZE     512
#define STR_SIZE    4

//...

void Proc(void)
{
    char buf[BUF_SIZE];        // Тут идут байты: 0xAA, 0xBB, 0xCC... 
    char str[STR_SIZE];        // Тут будет строчка для записи на диск
    int i, tmpchar;            // Счётчик цикла и временная переменная - для наглядности
    DWORD tmp;            // Вспомогательная переменная
    
    // ...
    // Открываю файлы, читаю буфер с диска, тут всё в порядке.
    // ...

    // А дальше - начинаю преобразовывать.
    for (i = 0; i < BUF_SIZE; i++)
    {
        tmpchar = buf[i];    // ОШИБКА!!!!
        snprintf(str, 3, "%x", tmpchar);
        str[2] = 0x0d;        // Вообще-то костыль, но пусть будет.
        str[3] = 0x0a;
        WriteFile(hFile, &str, STR_SIZE, &tmp, NULL);    // Функция Windows API
    }
}

И вот тут случился затык на выделенной строке — там, где большими буквами написано ОШИБКА!!!. tmpchar — целое число в 4 байта. В первом проходе цикла она была равна 0, а потом в неё попал первый символ буфера, и она стала равна 0x00_00_00_aa — всё в порядке, так и надо. А вот во втором проходе цикла в неё должна попасть величина 0x00_00_00_bb — а попадает постоянно 0xff_ff_ff_bb! Почему-то отрицательное число. Весь вечер долбался, мозги уже работать отказывались, поэтому воткнул туда следующий костыль:
        tmpchar = buf[i];    // ОШИБКА!!!!
        tmpchar &= 0xff;    // Жуткий костыль!!!
        snprintf(str, 3, "%x", tmpchar);

В таком виде — вроде заработало. Просветите меня, знающие люди, как всё-таки выглядит "правильный ответ"?
Re: Затык с преобразованием типов
От: Pavel Dvorkin Россия  
Дата: 07.04.15 05:26
Оценка:
Здравствуйте, TheMaster, Вы писали:

TM> unsigned char buf[BUF_SIZE]; // Тут идут байты: 0xAA, 0xBB, 0xCC...

TM> unsigned char str[STR_SIZE]; // Тут будет строчка для записи на диск
TM> unsigned int tmpchar; // Счётчик цикла и временная переменная — для наглядности
With best regards
Pavel Dvorkin
Re[2]: Затык с преобразованием типов
От: TheMaster  
Дата: 07.04.15 05:30
Оценка: -1
Здравствуйте, Pavel Dvorkin, Вы писали:

Спасибо за замечание!
Вечером доберусь домой — попробую.
Но даже если заработает — возникает вопрос: а почему так? Так, как я сделал, можно преобразовывать только переменные одинаковой длины, а если длина разная — могут быть вопросы с размерами/плюсами/минусами?
Re[3]: Затык с преобразованием типов
От: Pavel Dvorkin Россия  
Дата: 07.04.15 06:25
Оценка: +2
Здравствуйте, TheMaster, Вы писали:

TM>Но даже если заработает — возникает вопрос: а почему так? Так, как я сделал, можно преобразовывать только переменные одинаковой длины, а если длина разная — могут быть вопросы с размерами/плюсами/минусами?


Потому что 0xAA при представлении в виде char есть отрицательное число, а отрицательные числа хранятся в дополнительном коде, и при преобразовании в int , грубо говоря, добиваются единицами слева
With best regards
Pavel Dvorkin
Отредактировано 07.04.2015 7:27 Pavel Dvorkin . Предыдущая версия .
Re: Затык с преобразованием типов
От: Кодт Россия  
Дата: 07.04.15 13:18
Оценка:
Здравствуйте, TheMaster, Вы писали:

TM>        tmpchar = (unsigned char) buf[i];

Потому что char — по умолчанию — знаковый (это управляется опциями компилятора, но лучше это не трогать, а то сломается тысяча других мест).
Преобразование char --> int или char --> unsigned происходит по законам арифметики.
Т.е. char(0xFF) == char(-1), откуда (int)(char)(-1) = (int)(-1) = -1 = 0xF...FFF
Если же char с самого начала привести к unsigned char, (unsigned char)(char)(-1) = (unsigned char)(0xFF) = 255, далее (int)(255) = 255 = 0x0...0FF.

Теоретический базис нужно смотреть в стандартах Си и С++, но на пальцах и коротко суть вот такая.

Да, а переделывать тип массива, unsigned char buf[], — это уже на усмотрение. Насколько хочется подчеркнуть, что там "какие-то байты", а не "какие-то символы".
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.