关于C的 struct ,union我的一些看法

看到,一篇对 C++的 UNION如何被C#使用的问题帖。呵呵。内容很熟悉,包括那写结构体里面的东西,但是没办法回答,因为我曾经一度弱智到,认为C#和C sharp是两个东西。同时这玩意还要.net。我没学习他的原因一则,没时间,二则,花时间学了,究竟能用多久?以微软的作风,我不如好好学点类 UNIX上的工具。

回到正题上,无法回答C#的问题。这里就struct ,union上的东西谈下我自己的想法。书本上,和标准上说的东西我就不重复了。所以只是自己的想法。

向新手说union,我几乎不能回避struct。但前提是我只谈论的是C。其实那篇文章所写的,实际是C的union而不是C++的 union。不是我在嚼舌头,有迷糊的朋友可以google些C++的union的用法,再看看C是否支持。

在C++中,为了能对面向对象进行支持,使得union增加了对类成员方法的union的支持。但这个在C中是不存在的(没有支持的必要和存在性)

需要说明,union和struct在C里面(后面不再强调,此处不是谈C++),只是一个多数据类型的操作工具。给谁用?代码员和编译器。可以这 么说。没有union,struct的C仍然可以实现,包含了这两个保留字的所有C代码可实现的功能。只是方便程序员写代码而已。

例如我们存在描述的数据,这个数据存在不同的存储空间的字段。那么我们用struct来包裹,就非常方便。如下给出两个例子

01typedef struct {
02 int a;
03 char b;
04}_TEST_S;
05 
06_TEST_S test_s;
07 
08char return_TEST_S_b(_TEST_S *pt){
09   return pt->b;
10}
11 
12char return_test_ab_b(int *p){
13    return *(char*)(p+1);
14}
15int main(int argc ,char *argv[]){
16   char re_;
17   ...
18   re_ = return_TEST_S_b((_TEST_S *)&test_s);
19   re_ = return_test_ab_b((int*)&test_s);
20   ...
21}

以上两者实际是等同的。但_TEST_S和以下的方式完全不同。

1int test_a[10];
2char test_b[10];
3 
4char return_test_b(char *p){
5   return *p;
6}

这是因为,对于结构体,编译器看到的,每个存储单元,包含了一个int 和 char 两个类型的存储空间。因此对数组的任何一个下标的访问,他们是针对 具体存储单元锁定后,再找寻,该单元内,对应结构体内的具体类型的存储位置。

上述两者的差别非常像,以下两中构造数据表的操作。

我们把一个 “姓名” “年龄”的人的信息,放在一个表里,每个表的记录,包含两个字段,与我们有两张表,假设,表中对应记录的位置(下标)就是唯一ID号。那么每个表都只有一个字段。其中一个是“姓名”另一个是“年龄”

因此,struct只是用于打包,或规整数据之间存储位置的逻辑关系而使用的。方便于你有效描述你的目标逻辑(任务)。

同时C语言里,struct内,是不存在函数的,因为任何函数都是一个实际存在的代码片,用于执行的,struct的目的和功能我上面说了,因此无 法将多个函数进行打包。引申一下,多个函数进行位置打包的需求是客观存在的,但情况极少,通常用在对code cache有严格要求,或者函数位置和系统内部逻辑有关联的情况下。不过由于通过增加辅助信息,可以让编译器和连接器完成上述操作,因此C没有必要去用保 留字对函数打包操作。这是C与面向对象的C++不同的地方。C++的 类的概念,本身要求存在方法。而方法本身并不是数据而是一个实现函数的模版,其成为了类的一个必要组成部分。

回到 union,其实和struct很像,之不过,union的作用是多者选一个,而不是多个数据类型的整合描述。

例如下面的例子,我们做数组的全累加

01typedef union{
02   int i;
03   char c;
04}_TEST_U;
05#define MAX_TEST_U_NUM 10
06_TEST_U u[MAX_TEST_U_NUM];
07 
08int acc_test_U_i(_TEST_U *pt){
09   int i,re = 0;
10        
11   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
12      re += pt->i; pt++;
13   }
14   return re;
15}
16char acc_test_U_c(_TEST_U *pt){
17   int i;
18   char re = 0;//注意这里是会有溢出的,其实acc_test_U_i一样会有溢出,但此处不讨论这方面问题。
19        
20   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
21      re += pt->c; pt++;
22   }
23   return re;
24}

这个和下面两个函数,对比,记住,一个是错的,一个是正确的。

01int u[MAX_TEST_U_NUM];
02 
03int acc_test_U_i(void *p){//对
04   int i,re = 0;
05   int *pi = (int*)p;   
06   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
07      re += *pi++;
08   }
09   return re;
10}
11char acc_test_U_c(void *p){//错
12   int i;
13   char re = 0;
14   char *pc = (char *)p;   
15   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
16      re += *pc++;
17   }
18   return re;
19}

因为使用union,则允许整个程序里面,即可以 p->i ,也可以p->c。这是对同一个空间良种不同数据类型操作的差异,因为要保证所有可能的操作均有效。因此,空间必须按照可选择的数据类型中,最大的 一个分布。因此,以下的char的累加是对等 _TEST_U的。

01char acc_test_U_c(void *p){//对
02   int i;
03   char re = 0;
04   int *pi = (int *)p;   
05   char *pc;
06   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
07      pc = (char *)pi;
08      re += *pc;pi++;
09   }
10   return re;
11}
12//或者简单点
13char acc_test_U_c(void *p){
14   int i;
15   char re = 0;
16   char *pc = (char *)p;   
17   for (i = 0 ; i < MAX_TEST_U_NUM ; i++){
18 
19      re += *pc;pc+= sizeof(int)/sizeof(char); //这个地方我不怕除法,
20//因为编译器对于这类东西,会修正为常量,而不是每次弱智的去除
21   }
22   return re;
23 
24}

如果上述例子还是不能理解union的用法,那么下面我再做个例子,大家有兴趣可以尝试把结果打印一下。假设低位在前(LSB)的硬件系统

01typedef union{
02   int i;
03   char c;
04}_TEST_U;
05 
06_TEST_U u;
07 
08int main(int argc ,char *argv[]){
09   char *pc;
10   int i;
11   u.i = 0x01020304;
12   u.c = 0x5;
13   if ( u.i == 0x01020305){
14     //printf
15   }else{
16     //printf
17   }
18   pc = &(u.c);
19   for (i = 0 ; i < 4 ; i++){
20      pc[i] = 4 - i;
21   }
22   if (u.i == 0x04030201){
23//      printf(...
24   }else{
25    //printf..
26   }
27   ...
28}

和我其他的灌水帖一样,这篇灌水帖,包括代码都是临时写的,没验证,有漏笔之处,还望谅解。

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/luckystar/blog/56379

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值