标题: C语言经过位移运算把指针里面的值赋给变量为什么会在高八位上? [打印本页]

作者: yxyxyxyx    时间: 2022-10-13 11:18
标题: C语言经过位移运算把指针里面的值赋给变量为什么会在高八位上?

程序如下,用的是51单片机
#include "RX8F103.h"
#include "intrins.h"
#include <stdio.h>

//从串口发送一个字符
void EUart0_SendOneChar(char c)
{
        ES0=0;                                //发送数据时关串口中断
        TI0=0;                                //清TI位
        S0BUF = c;                //将待发送字符放入串口数据缓冲寄存器,并开始传输。
        while(!TI0);        //等待传送结束。当字符发送结束后由硬件置位请求中断,
                                                                //此时while循环结束,而串口中断处理函数需等到ES重新置1后才可能响应。
        TI0=0;                                //软件清TI位,亦可在中断处理函数中清0
        ES0 = 1;                        //开串口中断
}

void EUart0_SendString(char *st)
{
        while(*st)
        {
                EUart0_SendOneChar(*st++);
        }
}

unsigned char x[50] ={0x1e,0x00,0x00,0x00,0xca,0xfb,0x5f,0xf8,0x8f,0x00,0x1a,0x00,0x02,0xcf,0x81,
                      0xdb,0xff,0xe7,0xc8,0x00,0x20,0x00,0x01,0x5e,0x46,0xf5,0x71,0xd1,0x50,0x00,
                      0x21,0x00,0x01,0xa9,0xe1,0xfc,0xdf,0xc0,0x85,0x00,0x23,0x00,0x02,0xc8,0x44,
                      0xd7,0xf5,0xe9,0x47,0x00};


void main(void)
{        int a1=8;
        int a2=0x8f;
        int a3;

        unsigned char* iKeyP = x;
        CLKCON |= 0x1F;                                //默认所有时钟打开
        RSTPORTEN = 1;                                //使能复位功能

        UART0PORTEN = 1;                        //串口端口使能
        S0CON = 0x50;                                        //SCON: Mode 1, 8-bit UART, Enable Rcvr
        S0RELH = 0x03;                                //S0RELH + S0RELL  构成波特率设置S0REL[9:0]
        S0RELL = 0xF7;                                //Baud rate  = SYSCK/(16×(1024-S0REL))  SYSCK跟CLKDIV寄存器有关  波特率为115200
        ES0 = 1;                                                        //允许串口中断位
        EUart0_SendString("RX8F103 IIC Slave Init! V2.0\r\n");
        a1 = ((long)(a1)) << (9);
        a2 = (a2)+(128);
        a3 = *((short*)(iKeyP + (8)));
  while(1)
        {
                printf("Hello RX8F103 UART0\r\n");
                printf("a1==0x%x\r\n",a1);
                printf("a2==0x%x\r\n",a2);
                printf("a3==0x%x\r\n",a3);
        }
}

char putchar (char c)
{
        EUart0_SendOneChar(c);
        return c;
}

以下位打印的结果
RX8F103 IIC Slave Init! V2.0
Hello RX8F103 UART0
a1==0x1000
a2==0x10f
a3==0x8f00
问题在打印a3,a3不应该是a3=0x8f么,而是a3=0x8f00


作者: 624353765    时间: 2022-10-13 12:49
a3 = *((char*)(iKeyP + (8)));
这样才是8F
作者: Hephaestus    时间: 2022-10-13 13:36
qq624353765 发表于 2022-10-13 12:49
a3 = *((char*)(iKeyP + (8)));
这样才是8F

我没有c51,但是按说有符号数会扩展符号吧?8位的0x8f扩展成16位会当成负数扩展成0xff8f。
作者: glinfei    时间: 2022-10-13 15:09
没啥不对的啊,你强制类转换char型指针为short型,short每次走两个字节,于是读出来的是:0x8f,0x00两个数,不就是0x8f00
作者: Hephaestus    时间: 2022-10-13 18:27
glinfei 发表于 2022-10-13 15:09
没啥不对的啊,你强制类转换char型指针为short型,short每次走两个字节,于是读出来的是:0x8f,0x00两个数 ...

大端是0x8f00,小端是0x8f。

8位机本身根本就没有大小端问题,但是高级语言编译器有超过1字节的数据类型,那么必然就有大小端问题,取决于具体的编译器。对于8051来说,Keil C51是大端,IAR8051和SDCC是小端。
作者: 人中狼    时间: 2022-10-13 20:48
这个好像是数据在内存存储方式和C语言缺省排序的问题
作者: glinfei    时间: 2022-10-14 09:15
Hephaestus 发表于 2022-10-13 18:27
大端是0x8f00,小端是0x8f。

8位机本身根本就没有大小端问题,但是高级语言编译器有超过1字节的数据类 ...

这不是大小端问题,是偏巧下一个数字是0,它强制类转换成short,一次提取了两个字节,合并成一个数。如果加7,也就是 a3 = *((short*)(iKeyP + (7))); 那结果就是0xf88f
作者: Hephaestus    时间: 2022-10-14 12:07
glinfei 发表于 2022-10-14 09:15
这不是大小端问题,是偏巧下一个数字是0,它强制类转换成short,一次提取了两个字节,合并成一个数。如果 ...

short是两个字节,在内存里面必然有字节序问题,到底是高位在前(小地址)还是低位在前总要有个约定。

16位机、32位机有多字节指令,字节序由指令确定,你可以违反字节序,代价就是代码长度和运行时间的恶化。以Cortex-M为例,ARM卖出的内核是可以配置成大端或者小端模式,有一个标志位,芯片厂家生产的时候写死,一旦生产出来大端还是小端已经确定了,目前已知所有Cortex-M单片机都是小端模式。那么根据你的说法,下一数字偏巧是0,根据小端模式高字节在低地址的定义,提取出来的short就是0x008f。

这就叫大端和小端!
作者: 人中狼    时间: 2022-10-14 12:33
的确是大小端的问题,简单的说就是多字节数据在存储时地址方向的问题,就是存储地址是增加方向,还是减少方向的问题,不同的芯片会有不同的
作者: Hephaestus    时间: 2022-10-17 23:20
人中狼 发表于 2022-10-14 12:33
的确是大小端的问题,简单的说就是多字节数据在存储时地址方向的问题,就是存储地址是增加方向,还是减少方 ...

8位机哪来的什么大小端问题?但是编译器有多字节数据就有大小端问题。至少在8051这个平台上,大小端问题跟芯片无关,只跟编译器有关。
作者: QW192026    时间: 2022-10-18 09:17
51单片机字节存贮是大端模式

作者: Hephaestus    时间: 2022-10-18 10:23
QW192026 发表于 2022-10-18 09:17
51单片机字节存贮是大端模式

我在5楼的发言——

8位机本身根本就没有大小端问题,但是高级语言编译器有超过1字节的数据类型,那么必然就有大小端问题,取决于具体的编译器。对于8051来说,Keil C51是大端,IAR8051和SDCC是小端。

井底蛤蟆的天空可能只有碗口那么大。
作者: 耿晓峰    时间: 2022-10-18 16:58
qq624353765 发表于 2022-10-13 12:49
a3 = *((char*)(iKeyP + (8)));
这样才是8F

这是正解
作者: Hephaestus    时间: 2022-10-22 20:01
耿晓峰 发表于 2022-10-18 16:58
这是正解

16位数据截断成了8位数据,根本不符合要求,怎么就成了“正解”?
作者: Sean_Shao    时间: 2022-10-24 13:53
glinfei 发表于 2022-10-13 15:09
没啥不对的啊,你强制类转换char型指针为short型,short每次走两个字节,于是读出来的是:0x8f,0x00两个数 ...

4楼说得很对 不是 在高八位上 而是 按照short 类型 根据 你给的+8偏移量开始 在数组中取了两个字节 形成了0x8f00
作者: Sean_Shao    时间: 2022-10-24 14:03
问题的根源 应该还是在各平台对数据类型的定义的差异上 语言 编译器和硬件的相关文档 要拿出来对照




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1