user-0 提问: 关于socket通信中memcpy()把一个数组转换成结构体的问题

回复:
user: user-1
content: 引用 30 楼 xue_opnet 的回复:[quote=引用 26 楼 zhao4zhong1 的回复:] 楼主可以立即放下手头事情去街边买彩票了。 运气好到 sizeof(Gate)==strlen(Recv_Buf)+1 ！！！！！！！！！！！！！！！   Gate *clt=(Gate *)calloc(1, sizeof(Gate)); memcpy(clt,Recv_Buf,sizeof(Gate)); memmove(clt,Recv_Buf,sizeof(Gate)); 应改为 Gate *clt=(Gate *)calloc(1, sizeof(Gate)); sscanf(Recv_Buf,"%d%d%lf%lf%lf",&clt->tx_wave,&clt->gate_length,&clt->gate_length1,&clt->gate_length2,&clt->start_time); 谢谢您，五一回家没来得及及时回复您，之前我也用 sscanf(Recv_Buf,"%d%d%f%f%f",&clt->tx_wave,&clt->gate_length,&clt->gate_length1,&clt->gate_length2,&clt->start_time); 但是没有注意double类型的数据输入时不能用只能用%lf，所以每次编译到这一句程序就不执行了，现在改成%lf后结果正确了，谢谢您。[/quote]  printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方，而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。

user: user-1
content: 作为一个C程序员，对  scanf,sscanf,fscanf  printf,sprintf,fprintf 这类函数的用法，还是要做到“拳不离手，曲不离口”的。

user: user-2
content: #pragma pack(push) #pragma pack(1)  // 或2，4.。。。。。。。。。。。  声明结构体 #pragma pack(pop)

user: user-0
content: 引用 26 楼 zhao4zhong1 的回复:楼主可以立即放下手头事情去街边买彩票了。 运气好到 sizeof(Gate)==strlen(Recv_Buf)+1 ！！！！！！！！！！！！！！！   Gate *clt=(Gate *)calloc(1, sizeof(Gate)); memcpy(clt,Recv_Buf,sizeof(Gate)); memmove(clt,Recv_Buf,sizeof(Gate)); 应改为 Gate *clt=(Gate *)calloc(1, sizeof(Gate)); sscanf(Recv_Buf,"%d%d%lf%lf%lf",&clt->tx_wave,&clt->gate_length,&clt->gate_length1,&clt->gate_length2,&clt->start_time); 谢谢您，五一回家没来得及及时回复您，之前我也用 sscanf(Recv_Buf,"%d%d%f%f%f",&clt->tx_wave,&clt->gate_length,&clt->gate_length1,&clt->gate_length2,&clt->start_time); 但是没有注意double类型的数据输入时不能用只能用%lf，所以每次编译到这一句程序就不执行了，现在改成%lf后结果正确了，谢谢您。

user: user-0
content: 引用 24 楼 li9172 的回复:recv_buf能用%s打印,  说明你收到的是字符串, 而不是int/double类型的二进制码. 内存中的二进制表示都不一样, 不能用memcpy直接拷贝到结构体中, 要从recv_buf中一项项用atoi, atof转换才行. 你的服务端那边是拿fprintf做的结构体到send_buf转换? 服务端用sprintf做的转换 sprintf(Send_Buf,"%d %d %f %f %f",info->tx_wave,info-> gate_length,info-> gate_length1,info-> gate_length2,info->start_time);

user: user-1
content: 楼主可以立即放下手头事情去街边买彩票了。 运气好到 sizeof(Gate)==strlen(Recv_Buf)+1 ！！！！！！！！！！！！！！！   Gate *clt=(Gate *)calloc(1, sizeof(Gate)); memcpy(clt,Recv_Buf,sizeof(Gate)); memmove(clt,Recv_Buf,sizeof(Gate)); 应改为 Gate *clt=(Gate *)calloc(1, sizeof(Gate)); sscanf(Recv_Buf,"%d%d%lf%lf%lf",&clt->tx_wave,&clt->gate_length,&clt->gate_length1,&clt->gate_length2,&clt->start_time);

user: user-1
content: 请楼主把下面这段话倒背如流，每天象祥林嫂那样多念几遍： 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……

user: user-3
content: 引用 24 楼 li9172 的回复:recv_buf能用%s打印,  说明你收到的是字符串, 而不是int/double类型的二进制码. 内存中的二进制表示都不一样, 不能用memcpy直接拷贝到结构体中, 要从recv_buf中一项项用atoi, atof转换才行. 你的服务端那边是拿fprintf做的结构体到send_buf转换? 最后一行打错了, 不是fprintf ,是sprintf

user: user-3
content: recv_buf能用%s打印,  说明你收到的是字符串, 而不是int/double类型的二进制码. 内存中的二进制表示都不一样, 不能用memcpy直接拷贝到结构体中, 要从recv_buf中一项项用atoi, atof转换才行. 你的服务端那边是拿fprintf做的结构体到send_buf转换?

user: user-4
content: #pragma pack(1)  客户和服务端都加上这句，确定数据结构内部是紧凑的。  另外，客户机器和服务端机器的cpu大小端要一样。

user: user-5
content: 收藏

user: user-0
content: 引用 20 楼 zhao4zhong1 的回复:再供参考： 浮点数格式 http://bbs.csdn.net/topics/390676437 您好，用了您的代码看字节序，结果如下： 这样能说明问题吗？感觉两个int型变量分别占了两个字节，前两个double型变量占了8个字节，最后一个double变量占了9个字节，这是数组存储的时候出错了吗？

user: user-0
content: 引用 20 楼 zhao4zhong1 的回复:再供参考： 浮点数格式 http://bbs.csdn.net/topics/390676437 谢谢您，我再仔细查看一下是不是字节序的问题

user: user-1
content: 再供参考： 浮点数格式 http://bbs.csdn.net/topics/390676437

user: user-1
content: 如果总字节数和各结构体成员相对结构体开头的字节偏移量都一致没问题的话，那只剩下字节序了。 使用下面的HexDump函数看一下是不是字节序问题： void HexDump(char *buf,int len,int addr) {     int i,j,k;     char binstr[80];      for (i=0;i<len;i++) {         if (0==(i%16)) {             sprintf(binstr,"%08x -",i+addr);             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         } else if (15==(i%16)) {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);             sprintf(binstr,"%s  ",binstr);             for (j=i-15;j<=i;j++) {                 sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');             }             printf("%s\n",binstr);         } else {             sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);         }     }     if (0!=(i%16)) {         k=16-(i%16);         for (j=0;j<k;j++) {             sprintf(binstr,"%s   ",binstr);         }         sprintf(binstr,"%s  ",binstr);         k=16-k;         for (j=i-k;j<i;j++) {             sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');         }         printf("%s\n",binstr);     } }

user: user-1
content: 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,ftell,fread,fwrite,fgetc,fclose //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

user: user-0
content: 引用 16 楼 zhao4zhong1 的回复:结构体字节对齐惹的祸。 参考下面：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //  这是参考您的例子找出的结构体的存储位置： 可是怎么修改才会正确呢，我不明白您的意思，也不知道该怎么参考您的例子，数组中的内容就是按照int,int,double,double,double类型存储的，共32字节。结构体也是int,int,double,double,double共32字节，为什么会出错呢

user: user-1
content: 结构体字节对齐惹的祸。 参考下面：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //

user: user-0
content: 引用 14 楼 zhao4zhong1 的回复:不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊！ http://bbs.csdn.net/topics/380167545 您好，我定义了一个结构体typedef struct Gate 	{ int tx_wave; 	int gate_length; 	double gate_length1; 	double gate_length2; 	double start_time; 	    }Gate; 和一个数组char Recv_Buf[1024]; 该数组里的内容为1 2 3.000000 4.000000 20.000000 用么么move或memcopy语句把数组里的数据放进结构体力 Gate *clt=(Gate *)calloc(1, sizeof(Gate)); memcpy(clt,Recv_Buf,sizeof(Gate)); memmove(clt,Recv_Buf,sizeof(Gate)); 但结果却都错的 前两个变量有值，但是不正确并且都很大，是因为什么原因呢

user: user-1
content: 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊！ http://bbs.csdn.net/topics/380167545