Преобразование массива char в int с помощью strtol() в C

у меня возникли трудности с функцией strtol() в C, вот фрагмент кода того, как я пытаюсь ее использовать

char   TempChar;                        
char   SerialBuffer[21];
char   hexVoltage[2];
long   intVoltage;

 do
   {
     Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
     SerialBuffer[i] = TempChar;
     i++;
    }
  while (NoBytesRead > 0);

memcpy(hexVoltage, SerialBuffer+3, 2);

intVoltage = strtol(hexVoltage, NULL, 16);

Итак, вопрос в том, почему strtol() возвращает 0? И как преобразовать массив значений char в шестнадцатеричном формате в int (длинный в данном конкретном случае)? hexVoltage в моем случае содержит {03, 34} после memcpy(). Заранее спасибо. Очень ценю помощь здесь.


person sentenced    schedule 09.09.2016    source источник
comment
Вам нужно сделать его на один символ длиннее и завершить его нулем, иначе это не строка   -  person Baldrick    schedule 09.09.2016
comment
Пожалуйста, замените код чтения файла правильным минимально воспроизводимым примером. Это не имеет отношения к вашему вопросу и затрудняет воспроизведение проблемы.   -  person user694733    schedule 09.09.2016
comment
в моем случае содержит {03, 34}: тогда это вообще не может быть шестнадцатеричной строкой, это просто необработанные числа.   -  person Blagovest Buyukliev    schedule 09.09.2016
comment
Что вы ожидаете, что целое число будет содержать в конце?   -  person Baldrick    schedule 09.09.2016
comment
Пробовал с добавлением hexVoltage[2] = '\0'; после memcpy не повезло. Я хотел бы, чтобы целое число содержало 820, т.е. 0x0334 в десятичном формате. @BlagovestBuyukliev читаю ком порт,   -  person sentenced    schedule 09.09.2016
comment
Элемент hexVoltage[2] не существует. hexVoltage имеет только 2 элемента.   -  person user694733    schedule 09.09.2016
comment
@sentenced: вы читаете ASCII или двоичный файл?   -  person Blagovest Buyukliev    schedule 09.09.2016
comment
@user694733 user694733 я изменил char hexVoltage[2] на hexVoltage[3]   -  person sentenced    schedule 09.09.2016
comment
У нас действительно недостаточно информации в вопросе, чтобы понять, что представляют собой данные, откуда они взяты и как их следует преобразовать.   -  person Baldrick    schedule 09.09.2016


Ответы (1)


strtol и друзья ожидают, что вы предоставите им печатное представление номера в формате ASCII. Вместо этого вы предоставляете ему двоичную последовательность, которая считывается из файла (порта).

В этом случае ваш intVoltage можно вычислить, объединив два прочитанных байта в 2-байтовое число с побитовыми операциями, в зависимости от порядка байтов этих чисел на вашей платформе:

uint8_t binVoltage[2];
...
uint16_t intVoltage = binVoltage[0] | (binVoltage[1] << 8);
/* or */
uint16_t intVoltage = (binVoltage[0] << 8) | binVoltage[1];
person Blagovest Buyukliev    schedule 09.09.2016
comment
Кроме того, если порядок следования байтов известен на обоих концах, вы можете использовать union с двумя элементами, один uint8_t binVoltage[2], а другой uint16_t intVoltage, и преобразовать его таким образом. Я считаю, что это безопасно для строк, начиная с C99. - person Baldrick; 09.09.2016
comment
Спасибо большое, второй вариант сработал, я еще не совсем понял логику, но ты показал куда копать. - person sentenced; 09.09.2016
comment
Стандарт C не требует ASCII в качестве набора символов выполнения. - person too honest for this site; 09.09.2016
comment
@Baldrick: У этого есть проблемы с порядком байтов и т. Д. Лучше использовать сдвиги, пока вы не докажете, что это узкое место, и union решит его. - person too honest for this site; 09.09.2016
comment
Код вызывает неопределенное поведение для определенных значений в системах с 16-битным int. - person too honest for this site; 09.09.2016
comment
@Olaf: хочешь объяснить? Я полагаю, это из-за продвижения int левого операнда сдвигов? - person Blagovest Buyukliev; 09.09.2016