解引用char指针后,我得到了意外的输出

问题描述

我想使用char ptr从缓冲区中发送16位数据中的一些8位数据(HEX格式),为此,我采用了“ Unsigned short int”数组,并使用char取消引用了。但是在输出中,额外的“ FFFFFF”会附加到我的数据中。

代码段:


unsigned short int buf[50]={0},j;
char *ptr=buf;
//entering some 16bit data manually
buf[0]=0xAAAA;
buf[1]=0xCCBB;
buf[2]=0x1234;
buf[3]=0xABCD;

for(j=0;j<8;j++)
{
    printf("%X\t",*p);
    p++;
}

输出


FFFFFFAA FFFFFFAA FFFFFFBB FFFFFFCC 34 12 FFFFFFCD FFFFFFAB

对于0x1234数据,这里的格式正确,但是其余的如何处理。 谁能帮忙

解决方法

ptr指针的类型需要在此处取消签名:

unsigned short int buf[50]={0},j;
unsigned char *ptr=buf;
//entering some 16bit data manually
buf[0]=0xAAAA;
buf[1]=0xCCBB;
buf[2]=0x1234;
buf[3]=0xABCD;

for(j=0;j<8;j++)
{
    printf("%X\t",*ptr);
    ptr++;
}

将为您提供预期的输出:(字节顺序取决于您的字节序,这里是X86 / little-endian)

AA      AA      BB      CC      34      12      CD      AB
,
  • char *ptr=buf;这是无效的C。由于指针类型不兼容,因此这违反了“简单赋值”的约束。编译器必须为您提供诊断信息,例如警告。您可以通过在分配前进行投射来解决此问题:char*ptr = (char*)buf;

  • buf[1]=0xCCBB;等将无符号的short存储在内存中,并且像任何整数类型一样,它根据字节顺序存储。如果您使用的是低端字节序的x86 PC,则0xBB将存储在最低地址上。这就是为什么当您稍后逐字节打印它们时它们会向后出现的原因。

  • printf("%X\t",*ptr);这行上发生了很多奇怪的事情。

    • 首先,我们必须了解char具有实现定义的签名Is char signed or unsigned by default?。因此,这种类型绝对不能用于原始二进制操作或任何形式的算术。
    • 在您的特定编译器上,char刚好被签名。
    • printf是可变函数。这样的功能是奇特的(并且是不好的做法),并带有许多特殊规则。一条这样的特殊规则指出,传递给可变参数函数的每个参数都经过一种特殊的隐式提升,即“默认参数提升”。该规则说所有小整数类型(例如char)都被提升为类型int
    • 每当有符号的char或任何其他小整数类型被提升为较大的有符号类型时,它都是符号扩展,这意味着如果它持有一个负的十进制值,则该符号为保存。
    • 如果您的8位带符号的char指向数据0xAA,则它将被视为负数,因为0xAA是8位2的补码格式的-86十进制。当将此-86值转换为4字节带符号的int时,该符号将保留,但其值仍为-86。但是现在原始的二进制表示形式是0xFFFFFFAA。这就是为什么您的所有具有MSB设置的十六进制值字节都附加了0xFFFFFF ...,而没有MSB设置的那些却按预期方式打印的原因。
    • 最后,%X假定传递的参数是unsigned int,因此printf进行从内部int到值为-86的内部转换。无符号等效项0xFFFFFFAA,即打印出来的内容。

我们可以这样修改代码:

#include <stdio.h>
#include <stdint.h>

int main()
{
  uint16_t buf[50];
  uint8_t* ptr = (uint8_t*)buf;
  
  buf[0]=0xAAAA;
  buf[1]=0xCCBB;
  buf[2]=0x1234;
  buf[3]=0xABCD;

  for(int i=0; i<8; i++)
  {
      printf("%X\t",*ptr);
      ptr++;
  }
}

此处发生了将uint8_t升级为int的相同默认参数,但是这一次原始数据在升级之前被视为未签名,因此没有符号扩展发生。

,

首先,您的代码应如下所示;

unsigned short int buf[50] = {0},j;
char *ptr = (char *)buf;
//entering some 16bit data manually
buf[0] = 0xAAAA;
buf[1] = 0xCCBB;
buf[2] = 0x1234;
buf[3] = 0xABCD;

for (j = 0; j < 8; j++) {
    printf("%X ",*ptr); // "p" is not defined any where
    ptr++;               // i think,it's got to be "ptr"
}

关于FF...前缀:

  1. 前两行之后;

    a)50 * 2(short的大小)= 100字节被清零,

    b),然后将前8个字节分配为aa aa bb cc 34 12 cd ab

  2. 您的指针ptr(char *)(指向单个字节char),但是您的printf试图将它们打印为4个字节的整数。 / p>

  3. 由于*ptr取消引用单个字节,printf将其转换为4字节整数。您最好检查一下C书中有关char转换为int 二进制数的章节。基本上,这一章会告诉你;在从1字节转换为4字节的过程中,最左边的位向左复制。那是

  • 1 byte hex: aa1 byte bin: 10101010转换为4 byte bin: 11111111...10101010(最左边的1位在完成4个字节时被复制到左边;这里是FF前缀的所在来自)
  • 1 byte hex: 121 byte bin: 00010010转换为4 byte bin: 00000000...00010010(完成时,最左边的0位被复制到4个字节时被向左复制;全部归零,您看不到任何{{ 1}}前缀。