关于用memcpy拷贝结构体的问题?

clwk 2009-02-01 01:32:29
代码示例:
struct T_PARAMS
{
BYTE version;
BYTE sum;
short offset;
BYTE type;

short threshold;
BYTE level;
};

struct T_PARAMS t_DevPara={ 0x01,
0x00,
0x0000,
0x02,
0x0898,
0x0C
};

BYTE para_Arry[100];
memcpy(para_Arry, &t_DevPara, sizeof(t_DevPara) );
CString bdata;

bdata.Format("%x", para_Arry[5]);

结果发现para_Arry[5]= 0 而不是para_Arry[5] = 98; 实在是搞不清楚这个0 是从哪里来的,请教高人给指点一下?
如果给short threshold;注释掉, 赋值就正确,太奇怪了!!!


...全文
3765 60 打赏 收藏 转发到动态 举报
写回复
用AI写文章
60 条回复
切换为时间正序
请发表友善的回复…
发表回复
arong1234 2009-02-05
  • 打赏
  • 举报
回复
这叫“字节对齐”,不是字节序
[Quote=引用 59 楼 maenxiang 的回复:]
字节序问题,你的系统是小字节序的。pack(1)了
[/Quote]
maenxiang 2009-02-05
  • 打赏
  • 举报
回复
字节序问题,你的系统是小字节序的。pack(1)了
landylife01 2009-02-05
  • 打赏
  • 举报
回复
很明显 是 字节对齐问题
visir 2009-02-02
  • 打赏
  • 举报
回复
struct T_PARAMS
{
BYTE version; //para_Arry[0]
BYTE sum; //para_Arry[1]
short offset; //para_Arry[2],para_Arry[3]
BYTE type; //para_Arry[4],para_Arry[5]

short threshold;//para_Arry[6],para_Arry[7]
BYTE level; //para_Arry[8],para_Arry[9]
};

struct T_PARAMS t_DevPara={ 0x01, //para_Arry[0]=1
0x00, //para_Arry[1]=0
0x0000, //para_Arry[2]=0,para_Arry[3]=0
0x02, //para_Arry[4]=2,para_Arry[5]=无效
0x0898, //para_Arry[6]=152(十六进制的98),para_Arry[7]=8
0x0C //para_Arry[8]=12,para_Arry[9]=无效
};
这就是所谓的对齐. 最好的解决办法如上几楼所说, 调整一下字段的位置
arptest 2009-02-02
  • 打赏
  • 举报
回复
通过结构体赋值千万不能用memcpy
必须一个一个地读,不要怕麻烦,因为在C里面没有更好的办法了。当然也不推荐使用#pragma pack(1),这个知识权宜之计。
以前有些公司做的软件就是这样,很容易出错。
gql1123 2009-02-02
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 lann64 的回复:]
#pragma pack(1)
[/Quote]
up
ForestDB 2009-02-02
  • 打赏
  • 举报
回复
基本上还是比较同意各位的观点,给LZ一点建议,
C既可以是高级语言,也可以是低级语言,
从高级语言的观点来看,就尽量在抽象的层面来操作,不要尝试用memcpy这样很底层的内存操作,或者换句话来说,不要用byte的方式来访问struct的成员,因为有你不知道的事情发生(其实就是这里的许多高手说的内存对齐);
从低级语言的观点来看,C离机器不远,要从低级的层面发挥语言的效能,那势必得对底层有深入的了解才行,如果试图真正理解你的代码发生了什么,知道或者说理解底层的事是有必要的(举个简单的例子,int a = 0x12345678;你能够说出a的地址有什么特点吗?与a相关的内存的分布吗?然后在大小端上有什么注意的吗?如果a又是struct中的某个成员,又会有什么事发生吗?[内存对齐])。

至于为什么要内存对齐,则是又和硬件相关,简单的说,这样寻址效率最高,cpu时钟最少,大家所谓的编程,其实都是在一定的抽象层次上进行的,如果要穿透这个层次,则少不了对底层的理解。
xmu_才盛 2009-02-02
  • 打赏
  • 举报
回复
mark
zqz981 2009-02-02
  • 打赏
  • 举报
回复
咨询一下:
struct T_PARAMS t_DevPara={ 0x01,
0x00,
0x0000,
0x02,
0x0898,
0x0C
};
这些 0x01 0x00, 是什么东西? 内存地址吗?
shinefree2004 2009-02-02
  • 打赏
  • 举报
回复
mark
lightbear 2009-02-02
  • 打赏
  • 举报
回复
学习了
yutaooo 2009-02-01
  • 打赏
  • 举报
回复

LZ 应该把原始需求说一下。我想,把结构复制给一个数组,也许是为了和远端进行通信。或者,放入一个低级别的数据库(如bdb)。

针对性的技术有好多种,从类似LZ这样简单内存拷贝到完整的整编解编库。代价也各不相同。

信息多一点,思维开阔点,有完美解决方案的。
xidianxiancai 2009-02-01
  • 打赏
  • 举报
回复
学习了。
waizqfor 2009-02-01
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 arong1234 的回复:]
1。 把对象转变成字节数组的技术叫serialization,这种技术不是要求字节数组的内容和对象的各个数据成员依次相等,你所谓的“准确”的数据,这个概念就是错误的,为什么多个0就不准确了?为了性能中间插入几个字节,这是现代非常流行的以空间换时间思想的体现,这是技术(我不敢加其他修饰,老实说,这只是非常普通的技术),不是错误,也不是问题。
2. 访问数据内容应该用他准确的类型去访问,转换为字节序列只是为了存储或者…
[/Quote]
拿板凳 听荣哥讲课!~~ UP
xqhrs232 2009-02-01
  • 打赏
  • 举报
回复
学习一下
arong1234 2009-02-01
  • 打赏
  • 举报
回复
至于为什么不缺省pack(1),你看看这个http://blog.csdn.net/arong1234/archive/2008/03/23/2210462.aspx
arong1234 2009-02-01
  • 打赏
  • 举报
回复
1。 把对象转变成字节数组的技术叫serialization,这种技术不是要求字节数组的内容和对象的各个数据成员依次相等,你所谓的“准确”的数据,这个概念就是错误的,为什么多个0就不准确了?为了性能中间插入几个字节,这是现代非常流行的以空间换时间思想的体现,这是技术(我不敢加其他修饰,老实说,这只是非常普通的技术),不是错误,也不是问题。
2. 访问数据内容应该用他准确的类型去访问,转换为字节序列只是为了存储或者传输。因此访问这个结构还是用结构指针,而不是那个字节array
3. 至于pack(1), pack(n)的概念,MSDN都有,我就不说了

[Quote=引用 40 楼 clwk 的回复:]
说得好,你说的每一句都很精辟,所以才想你请教,你问我的问题我都没法回答你,除非我再去搜索别的答案,但这样没有意义,如果您有空的话,可否给讲讲呢?

BTW,我遇到的问题,只是因为我要用到的struct是被定义好的,我这里只能去read,所以我也知道是否有别的简单方法去访问这个结构会更合适,如果有的话,请给指教了,多谢!
[/Quote]
xiaoshu666 2009-02-01
  • 打赏
  • 举报
回复
支持 39楼的
从根本上解决问题才是硬道理!
clwk 2009-02-01
  • 打赏
  • 举报
回复
才知道,要明天才能加分。
clwk 2009-02-01
  • 打赏
  • 举报
回复
看来这个帖子是要再多加分了。。。
加载更多回复(40)
1 愉快的开始-HELLO WORLD 14 1.1 INCLUDE头文件包含 14 1.2 MAIN函数 14 1.3 注释 14 1.4 {}括号,程序题和代码块 14 1.5 声明 14 1.6 C语言自定义名字的要求 15 1.7 PRINTF函数 15 1.8 RETURN语句 15 1.9 SYSTEM系统调用 15 1.9.1 System返回值在windows和unix下的不同, 15 1.9.2 POSIX 15 1.10 C语言编译过程,GCC参数简介 16 1.10.1 C语言编译过程 16 1.10.2 -E预编译 16 1.10.3 -S汇编 16 1.10.4 -c编译 16 1.10.5 链接 16 1.11 操作系统结构 17 1.11.1 用户模式 17 1.11.2 内核模式 17 1.12 64位,32位系统区别 18 1.12.1 CPU内部结构与寄存器 18 1.12.2 RISC与CISC CPU构架 18 1.12.3 SPARC,x86与ARM 18 1.13 汇编语言 18 1.13.1 I386汇编简介 18 1.13.2 VS反汇编 19 1.14 IDE工具 19 1.14.1 QT常用快捷键 19 1.14.2 VS常用快捷键 19 1.14.3 VS断点,调试 19 2 C语言中的数据类型 19 2.1 常量 19 2.1.1 #define 19 2.1.2 const 19 2.2 字符串常量 20 2.3 二进制数、位、字节与字 20 2.4 八进制 20 2.5 十六进制 20 2.6 原码 21 2.7 反码 21 2.8 补码 21 2.9 SIZEOF关键字 22 2.10 INT类型 22 2.10.1 int常量,变量 22 2.10.2 printf输出int值 23 2.10.3 printf输出八进制和十六进制 23 2.10.4 short,long,long long,unsigned int 23 2.10.5 整数溢出 23 2.10.6 大端对齐与小端对齐 23 2.11 CHAR类型 24 2.11.1 char常量,变量 24 2.11.2 printf输出char 24 2.11.3 不可打印char转义符 24 2.11.4 char和unsigned char 25 2.12 浮点FLOAT,DOUBLE,LONG DOUBLE类型 25 2.12.1 浮点常量,变量 25 2.12.2 printf输出浮点数 25 2.13 类型限定 25 2.13.1 const 25 2.13.2 volatile 26 2.13.3 register 26 3 字符串格式化输出和输入 26 3.1 字符串在计算机内部的存储方式 26 3.2 PRINTF函数,PUTCHAR函数 27 3.3 SCANF函数与GETCHAR函数 28 4 运算符表达式和语句 29 4.1 基本运算符 29 4.1.1 = 29 4.1.2 + 29 4.1.3 – 29 4.1.4 * 29 4.1.5 / 29 4.1.6 % 29 4.1.7 += 29 4.1.8 -= 29 4.1.9 *= 29 4.1.10 /= 30 4.1.11 %= 30 4.1.12 ++ 30 4.1.13 -- 30 4.1.14 逗号运算符 30 4.1.15 运算符优先级 30 4.2 复合语句 31 4.3 空语句 31 4.4 类型转化 31 5 条件分支语句 31 5.1 关系运算符 31 5.1.1 < 31 5.1.2 <= 31 5.1.3 > 32 5.1.4 >= 32 5.1.5 == 32 5.1.6 != 32 5.2 关系运算符优先级 32 5.3 逻辑运算符 32 5.3.1 && 32 5.3.2 || 32 5.3.3 ! 33 5.4 IF 33 5.5 IF ELSE 34 5.6 IF ELSE IF 34 5.7 SWITCH与BREAK,DEFAULT 35 5.8 条件运算符? 36 5.9 GOTO语句与标号 36 6 循环语句 36 6.1 WHILE 36 6.2 CONTINUE 37 6.3 BREAK 37 6.4 DO WHILE 37 6.5 FOR 37 6.6 循环嵌套 37 7 数组 38 7.1 一维数组定义与使用 38 7.2 数组在内存的存储方式 38 7.3 一维数组初始化 38 7.4 二维数组定义与使用 39 7.5 二维数组初始化 39 8 字符串与字符数组 39 8.1 字符数组定义 39 8.2 字符数组初始化 39 8.3 字符数组使用 40 8.4 随机数产生函数RAND与SRAND 40 8.5 用SCANF输入字符串 40 8.6 字符串的结束标志 41 8.7 字符串处理函数 41 8.7.1 gets 41 8.7.2 fgets函数 41 8.7.3 puts函数 42 8.7.4 fputs函数 42 8.7.5 strlen,字符串长度 42 8.7.6 strcat,字符串追加 42 8.7.7 strncat,字符串有限追加 43 8.7.8 strcmp,字符串比较 43 8.7.9 strncmp,字符串有限比较 43 8.7.10 strcpy字符串拷贝 43 8.7.11 strncpy字符串有限拷贝 43 8.7.12 sprintf,格式化字符串 43 8.7.13 Sscanf函数 44 8.7.14 strchr查找字符 44 8.7.15 strstr查找子串 44 8.7.16 strtok分割字符串 44 8.7.17 atoi转化为int 45 8.7.18 atof转化为float 45 8.7.19 atol转化为long 45 9 函数 45 9.1 函数的原型和调用 45 9.2 函数的形参与实参 45 9.3 函数的返回类型与返回值 46 9.4 MAIN函数与EXIT函数与函数的RETURN语句 46 9.5 多个源代码文件程序的编译 47 9.5.1 头文件的使用 47 9.5.2 #include与#define的意义 47 9.5.3 #ifndef与#endif 47 9.6 函数的递归 48 9.6.1 递归的过程分析 48 9.6.2 递归的优点 52 9.6.3 递归的缺点 52 1 指针 52 1.1 指针 52 1.1.1 指针的概念 52 1.1.2 指针变量的定义 52 1.1.3 &取地址运算符 52 1.1.4 无类型指针 52 1.1.5 NULL 53 1.1.6 空指针与野指针 53 1.1.7 指针的兼容性 53 1.1.8 指向常量的指针与指针常量 54 1.1.9 指针与数组的关系 54 1.1.10 指针运算 54 1.1.11 通过指针使用数组元素 55 1.1.12 指针数组 55 1.1.13 指向指针的指针(二级指针) 55 1.1.14 指向二维数组的指针 57 1.1.15 指针变量做为函数的参数 57 1.1.16 一维数组名作为函数参数 57 1.1.17 二维数组名作为函数参数 58 1.1.18 const关键字保护数组内容 58 1.1.19 指针做为函数的返回值 58 1.1.20 指向函数的指针 59 1.1.21 把指向函数的指针做为函数的参数 60 1.1.22 memset,memcpy,memmove函数 61 1.1.23 指针小结 63 2 字符指针与字符串 64 2.1 指针和字符串 64 2.2 通过指针访问字符串数组 64 2.3 函数的参数为CHAR * 64 2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 作用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块作用域的静态变量 66 3.1.4 代码块作用域外的静态变量 66 3.1.5 全局变量 66 3.1.6 外部变量与extern关键字 66 3.1.7 全局函数和静态函数 66 3.2 内存四区 66 3.2.1 代码区 67 3.2.2 静态区 67 3.2.3 栈区 67 3.2.4 栈溢出 68 3.2.5 堆区 68 3.3 堆的分配和释放 70 3.3.1 malloc 70 3.3.2 free 70 3.3.3 calloc: 70 3.3.4 realloc 71 4 结构体,联合体,枚举与TYPEDEF 71 4.1 结构体 71 4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组的指针 73 4.1.10 结构中的数组成员和指针成员 73 4.1.11 在堆中创建的结构体 74 4.1.12 将结构作为函数参数 74 4.1.13 结构,还是指向结构的指针 74 4.2 联合体 75 4.3 枚举类型 75 4.3.1 枚举定义 75 4.3.2 默认值 76 4.4 TYPEDEF 76 4.5 通过TYPEDEF定义函数指针 76 5 文件操作 77 5.1 FOPEN 77 5.2 二进制和文本模式的区别 77 5.3 FCLOSE 78 5.4 GETC和PUTC函数 78 5.5 EOF与FEOF函数文件结尾 78 5.6 FPRINTF,FSCANF,FGETS,FPUTS函数 78 5.7 STAT函数 78 5.8 FREAD和FWRITE函数 79 5.9 FREAD与FEOF 79 5.10 通过FWRITE将结构保存到二进制文件中 79 5.11 FSEEK函数 80 5.12 FTELL函数 80 5.13 FFLUSH函数 80 5.14 REMOVE函数 81 5.15 RENAME函数 81 6 基础数据结构与算法 82 6.1 什么是数据结构 82 6.2 什么是算法 82 6.3 排序 83 6.3.1 冒泡排序 83 6.3.2 选择排序 83 6.4 查找 83 6.4.1 顺序查找 83 6.4.2 二分查找 83 6.5 链表 84 6.5.1 单向链表定义 84 6.5.2 单向链表数据结构定义 85 6.5.3 单向链表的实现 85

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧