从文件中读取十六进制并将2字节转换为Signed int

时间:2015-08-17 08:51:32

标签: c

我有这种格式的文件:

F2,80,FF,CF,0F,00,A2,XXXX,XXXX,XXXX,01FE,00

我需要取字节3和4并将它们组合成有符号整数。

例如,我应该提取FFCF并将它们合并到0xFFCF。这应该给我一个有符号值的-49

我的代码在这里:

int main()
{
 char buffer[1024] ;
 char *record,*line;
 uint8_t val;
 uint8_t msb, lsb; 
 int16_t rate;
 int i=0,j=0;
 int mat[100][100];
 FILE *fstream = fopen("log1.txt","r");
 if(fstream == NULL)
 {
   printf("\n file opening failed ");
   return -1 ;
 }

while((line=fgets(buffer,sizeof(buffer),fstream))!=NULL)
{
 record = strtok(line,",");
 int count = 0;
 while(record != NULL)
 {
    count++;
    if (count == 3)
    { 
        printf("string:%s\n", record);
        sscanf(record, "%02X", &msb);

        printf("MSB: %01X\n",msb) ;    
    }
    if (count == 4)
    {
        printf("string:%s\n", record);
        sscanf(record, "%02X", &lsb);
        printf("lsb: %01X\n",lsb);  
    }
    if (count == 5)
    {
    int16_t value = (short)(((msb) & 0xFF) << 8 | (lsb) & 0xFF);
    printf("rate: %.2f\n", value*0.03125);
        getchar();
    }
    record = strtok(NULL,",");
 }
 ++i ;
}
return 0;
}

我从代码中看到的确切输出是:

string:FF
MSB: FF
string:CD
lsb: CD
HEX: 00CD
rate: 6.41

我希望率为:-1.59

我似乎从来没有看到负数,而且我得到的数值太小了。

4 个答案:

答案 0 :(得分:1)

不是使用不同的变量类型来尝试获得你想要的行为,而是如何明确它呢?像这样:

#include <stdio.h>

int main(int argc, char *argv[]) 
{
    int msb = 0xff;
    int lsb = 0xcf;

    int value = (((msb & 0xff) << 8) | (lsb & 0xff));
    if (value >= 0x8000) value = -(0x10000 - value);

    printf("%d\n", value);

    return 0;
}

答案 1 :(得分:0)

以下是我如何使用代码:

int16_t hexToInt(char* msb, char* lsb)
{
    char toparse[50];
    strcpy(toparse, msb);
    strcat(toparse,lsb);

    int16_t number = (int16_t)strtol(toparse, NULL, 16);
    return number;
}


int main()
{
char buffer[1024] ;
char *record,*line;
uint8_t val;
char msb[16], lsb[16]; 
int16_t rate;

FILE *fstream = fopen("log1.txt","r");
if(fstream == NULL)
{
  printf("\n file opening failed ");
  return -1 ;
}

while((line=fgets(buffer,sizeof(buffer),fstream))!=NULL)
{
 record = strtok(line,",");
 int count = 0;
 while(record != NULL)
 {
    count++;
    if (count == 3)
    { 
        printf("string:%s\n", record);
        strcpy(msb, record);


    }
    if (count == 4)
    {
        printf("string:%s\n", record);
        strcpy(lsb,record);

    }
    if (count == 5)
    {
        int16_t value = hexToInt(msb,lsb);
        printf("rate: %.2f\n", value*0.03125);
        getchar();
    }
    record = strtok(NULL,",");
  }
  ++i ;
}
return 0;
}

答案 2 :(得分:0)

该值确实是0xFFCF,但是当与0.03125相乘时,它会被提升为更高的数据类型,因为哪个值会丢失其签名。

只需更改

printf("rate: %.2f\n", value*0.03125);

printf("rate: %.2f\n", ((short)value*0.03125));

值为-49 or 0xFFCF时输出为

rate: -1.53

答案 3 :(得分:0)

代码具有未定义的行为。 OP的代码尝试将int大小的结果保存到1字节的位置。一个好的编译器或启用了警告的编译器会警告这个问题。

uint8_t msb, lsb; 
...
sscanf(record, "%02X", &msb);
sscanf(record, "%02X", &lsb);

代码可以使用正确的scanf()说明符

#include <inttypes.h>
sscanf(record, "%02" SCNx8, &msb);
sscanf(record, "%02" SCNx8, &lsb);

或只是一个不同的类型

unsigned msb, lsb; 
...
sscanf(record, "%02X", &msb);
sscanf(record, "%02X", &lsb);

OP的转换是可疑的:

uint8_t msb, lsb; 
int16_t value = (short)(((msb) & 0xFF) << 8 | (lsb) & 0xFF);
printf("rate: %.2f\n", value*0.03125);

建议类似@John Bickers的内容即使int为16位,以下内容仍可正常工作。

long value = msb;
value <<= 8;
value += lsb;
if (value >= 0x8000) value -= 0x10000;
printf("value %ld\n", value);
// -49 *  0.03125 --> "-1.53"
printf("rate: %.2f\n", value * 0.03125);

由于OP预计从-49缩小到-15.6,可能需要按1 / pi缩放而不是* 0.03125