关于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来包裹,就非常方便。如下给出两个例子

01 typedef struct {
02  int a;
03  char b;
04 }_TEST_S;
05  
06 _TEST_S test_s;
07  
08 char return_TEST_S_b(_TEST_S *pt){
09    return pt->b;
10 }
11  
12 char return_test_ab_b(int *p){
13     return *(char*)(p+1);
14 }
15 int 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和以下的方式完全不同。

1 int test_a[10];
2 char test_b[10];
3  
4 char 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的作用是多者选一个,而不是多个数据类型的整合描述。

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

01 typedef 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  
08 int 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 }
16 char 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 }

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

01 int u[MAX_TEST_U_NUM];
02  
03 int 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 }
11 char 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的。

01 char 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 //或者简单点
13 char 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)的硬件系统

01 typedef union{
02    int i;
03    char c;
04 }_TEST_U;
05  
06 _TEST_U u;
07  
08 int 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 }

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

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(关于C的 struct ,union我的一些看法)