您的位置: 首页 - 站长

VM2008 做网站如何建立公司网站推广

当前位置: 首页 > news >正文

VM2008 做网站,如何建立公司网站推广,华为官方商城网站建设方案,网站开发 京东【C语言】数据指针的取值、赋值、自增操作避坑 文章目录 指针地址指针自增指针取值、赋值附录#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Packed-ASCII字符串 大小端转换什么是大端和小端数据传输中的大小端总结大小端转换函数 指针地址 请看下列代码#…【C语言】数据指针的取值、赋值、自增操作避坑 文章目录 指针地址指针自增指针取值、赋值附录压缩字符串、大小端格式转换压缩字符串浮点数压缩Packed-ASCII字符串 大小端转换什么是大端和小端数据传输中的大小端总结大小端转换函数 指针地址 请看下列代码 #includestdio.h #includestdint.h #includestring.h #include stdio.h #include string.h uint8_t buf[10]{0x3F,0xaa,0x3E,0xbb,0xAA,0x3F,0xaa,0x3E,0xbb,0xAA};int main() {void * pbuf[0];uint8_t* p0p;uint16_t* p1p;uint32_t* p2p;float * p3 p;uint8_t i0;for(i0;i10;i){printf(%u ,buf[i]);}printf(\n);printf(p:%u p0:%u p1:%u p2:%u p3:%u \n,p,p0,p1,p2,p3);p;p0;p1;p2;p3;printf(p:%u p0:%u p1:%u p2:%u p3:%u \n,p,p0,p1,p2,p3);printf(%x\n,(uint16_t)p0);printf(%x\n,(uint16_t*)p0);return 0; } 先不看答案 先思考 已知buf的地址为4206608 那么这几个printf的输出分别是哪些数 默认为小端格式 如果你能完全搞懂 那么就没必要继续往下看了 如果不明白指针是什么意思 那么请先去学指针 输出结果是 4206608 4206609 4206610 4206611 4206612 4206613 4206614 4206615 4206616 4206617 p:4206608 p0:4206608 p1:4206608 p2:4206608 p3:4206608 p:4206609 p0:4206609 p1:4206610 p2:4206612 p3:4206612 aa 3eaa指针自增 除了void类型 其他的指针地址都有自己的类型 而不同的类型对应的数据结构 大小也不一样 void指针可以单纯表示地址 其自增时地址1 uint8_t类型大小也是1字节 所以自增地址1 uint16_t类型大小 2字节 所以自增地址2 uint32_t类型大小4字节 自增地址4 float类型大小4字节 自增地址4 所以得到 自增前后的地址为 p:4206608 p0:4206608 p1:4206608 p2:4206608 p3:4206608 p:4206609 p0:4206609 p1:4206610 p2:4206612 p3:4206612 指针取值、赋值 经过上一次的自增p0的地址为4206609 在buf中对应的是0xaa 对于取值(uint16_t)p0其逻辑为先取值 再转为uint16_t 所以是先得到uint8_t类型的0xaa 然后再做赋值操作 得到uint16_t类型的0x00aa 对于取值(uint16_t*)p0 其逻辑为先转为uint16_t*类型的指针地址 再取值 在转为uint16_t*类型的指针地址后 其地址对应的数为uint16_t类型的0x3eaa 取值后自然就是0x3eaa 附录压缩字符串、大小端格式转换 压缩字符串 首先HART数据格式如下 重点就是浮点数和字符串类型 Latin-1就不说了 基本用不到 浮点数 浮点数里面 如 0x40 80 00 00表示4.0f 在HART协议里面 浮点数是按大端格式发送的 就是高位先发送 低位后发送 发送出来的数组为40,80,00,00 但在C语言对浮点数的存储中 是按小端格式来存储的 也就是40在高位 00在低位 浮点数4.0f 地址0x1000对应00 地址0x1001对应00 地址0x1002对应80 地址0x1003对应40 若直接使用memcpy函数 则需要进行大小端转换 否则会存储为 地址0x1000对应40 地址0x1001对应80 地址0x1002对应00 地址0x1003对应00 大小端转换 void swap32(void * p) {uint32_t *ptrp;uint32_t x *ptr;x (x 16) | (x 16);x ((x 0x00FF00FF) 8) | ((x 8) 0x00FF00FF);*ptrx; } 压缩Packed-ASCII字符串 本质上是将原本的ASCII的最高2位去掉 然后拼接起来 比如空格(0x20) 四个空格拼接后就成了 1000 0010 0000 1000 0010 0000 十六进制82 08 20 对了一下表 0x20之前的识别不了 也就是只能识别0x20-0x5F的ASCII表
压缩/解压函数后面再写 //传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数 uint8_t Trans_ASCII_to_Pack(uint8_t * str,uint8_t * buf,const uint8_t str_len) {if(str_len%4){return 0;}uint8_t i0;memset(buf,0,str_len/4*3); for(i0;istr_len;i){if(str[i]0x00){str[i]0x20;}}for(i0;istr_len/4;i){buf3*i|((str[4*i1]4)0x03);buf3*i1|((str[4*i2]2)0x0F);buf3*i2|(str[4*i3]0x3F);}return 1; }//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数 uint8_t Trans_Pack_to_ASCII(uint8_t * str,uint8_t * buf,const uint8_t str_len) {if(str_len%4){return 0;}uint8_t i0;memset(str,0,str_len);for(i0;istr_len/4;i){str4*i0x3F;str4*i1|(buf[3*i1]4);str4*i2|(buf[3*i2]6);str[4*i3]buf[3i2]0x3F;}return 1; } 大小端转换 在串口等数据解析中 难免遇到大小端格式问题 什么是大端和小端 所谓的大端模式就是高位字节排放在内存的低地址端低位字节排放在内存的高地址端。 所谓的小端模式就是低位字节排放在内存的低地址端高位字节排放在内存的高地址端。 简单来说大端——高尾端小端——低尾端 举个例子比如数字 0x12 34 56 78在内存中的表示形式为 1)大端模式 低地址 —————– 高地址 0x12 | 0x34 | 0x56 | 0x78 2)小端模式 低地址 —————— 高地址 0x78 | 0x56 | 0x34 | 0x12 可见大端模式和字符串的存储模式类似。 数据传输中的大小端 比如地址位、起止位一般都是大端格式 如 起始位0x520A 则发送的buf应为{0x52,0x0A} 而数据位一般是小端格式单字节无大小端之分 如 一个16位的数据发送出来为{0x52,0x0A} 则对应的uint16_t类型数为 0x0A52 而对于浮点数4.0f 转为32位应是 40 80 00 00 以大端存储来说 发送出来的buf就是依次发送 40 80 00 00 以小端存储来说 则发送 00 00 80 40 由于memcpy等函数 是按字节地址进行复制 其复制的格式为小端格式 所以当数据为小端存储时 不用进行大小端转换 如 uint32_t dat0; uint8_t buf[]{0x00,0x00,0x80,0x40};memcpy(dat,buf,4);float f0.0f;f((float)dat); //地址强转printf(%f,f);或更优解 uint8_t buf[]{0x00,0x00,0x80,0x40}; float f0.0f;memcpy(f,buf,4);而对于大端存储的数据如HART协议数据 全为大端格式 其复制的格式仍然为小端格式 所以当数据为小端存储时 要进行大小端转换 如 uint32_t dat0; uint8_t buf[]{0x40,0x80,0x00,0x00};memcpy(dat,buf,4);float f0.0f;swap32(dat); //大小端转换f((float)dat); //地址强转printf(%f,f);或 uint8_t buf[]{0x40,0x80,0x00,0x00};memcpy(dat,buf,4);float f0.0f;swap32(f); //大小端转换printf(%f,f);或更优解 uint32_t dat0; uint8_t buf[]{0x40,0x80,0x00,0x00};float f0.0f;dat(buf[0]24)|(buf[0]16)|(buf[0]8)|(buf[0]0)f((float*)dat);总结 固 若数据为小端格式 则可以直接用memcpy函数进行转换 否则通过移位的方式再进行地址强转 对于多位数据 比如同时传两个浮点数 则可以定义结构体之后进行memcpy复制数据为小端格式 对于小端数据 直接用memcpy写入即可 若是浮点数 也不用再进行强转 对于大端数据 如果不嫌麻烦 或想使代码更加简洁但执行效率会降低 也可以先用memcpy写入结构体之后再调用大小端转换函数 但这里需要注意的是 结构体必须全为无符号整型 浮点型只能在大小端转换写入之后再次强转 若结构体内采用浮点型 则需要强转两次 所以对于大端数据 推荐通过移位的方式来进行赋值 然后再进行个别数的强转 再往通用结构体进行写入 多个不同变量大小的结构体 要主要字节对齐的问题 可以用#pragma pack(1) 使其对齐为1 但会影响效率 大小端转换函数 直接通过对地址的操作来实现 传入的变量为32位的变量 中间变量ptr是传入变量的地址 void swap16(void * p) {uint16_t *ptrp;uint16_t x *ptr;x (x 8) | (x 8);*ptrx; }void swap32(void * p) {uint32_t *ptrp;uint32_t x *ptr;x (x 16) | (x 16);x ((x 0x00FF00FF) 8) | ((x 8) 0x00FF00FF);*ptrx; }void swap64(void * p) {uint64_t *ptrp;uint64_t x *ptr;x (x 32) | (x 32);x ((x 0x0000FFFF0000FFFF) 16) | ((x 16) 0x0000FFFF0000FFFF);x ((x 0x00FF00FF00FF00FF) 8) | ((x 8) 0x00FF00FF00FF00FF);*ptrx; }