结构、联合、位字段、枚举

来源:互联网 发布:淘宝旺旺头像 编辑:程序博客网 时间:2024/06/05 15:08

结构

结构体在声明的时候并没有分配任何的内存资源,只有定义了结构体变量才会产生相应的内存分配。

typedef和#define的区别

#define仅仅是做简单的替换,而typedef是给某种数据类型创建一个替代名。 
看这样的例子:

#include <stdio.h>#define charP char*int main(){    charP s1="I love you.", s2="hello";    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编译:

$ gcc typedef.c typedef.c: In function ‘main’:typedef.c:4:29: warning: initialization makes integer from pointer without a cast  charP s1="I love you.", s2="hello";                             ^
  • 1
  • 2
  • 3
  • 4
  • 5

typedef:

#include <stdio.h>typedef char* charP;int main(){    charP s1="I love you.", s2="hello";    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编译:

$ gcc typedef.c
  • 1

结构体直接赋值

#include <stdio.h>typedef struct node{    char *s;    int a;    float b;}Node;int main(){    Node A;    A.s = "hello";    A.a = 12;    A.b = 2.5;    Node B = A;    printf("s is %s, a is %d, b is %f\n",B.s,B.a,B.b);    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
#include <stdio.h>#include <string.h>typedef struct node{    char s[30];    int a;    float b;}Node;int main(){    Node A;    strcpy(A.s,"hello");    A.a = 12;    A.b = 2.5;    Node B = A;    printf("s is %s, a is %d, b is %f\n",B.s,B.a,B.b);    return 0;}/*edemon@ubuntu1:~/workspace$ ./a.out s is hello, a is 12, b is 2.500000*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

结构体的嵌套

结构体定义中含有另一种结构体,这是合法的:

struct point{    int x,y;};struct trangle{    struct point p[3]; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

但是含有自身类型就是非法的了。

struct trangle{    struct trangle p[3]; };/*$ gcc struct1.c struct1.c:8:17: error: array type has incomplete element type  struct trangle p[3];                  ^*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结构体定义中可以拥有指向自身类型结构的指针。这样的自指结构是合法的。

struct trangle{    struct trangle* p[3]; };
  • 1
  • 2
  • 3

自指结构最典型的应用就是链表。

结构体定义的注意点

和C++不同,C不能在结构体中定义函数,因为C约定结构和算法(函数)是分开的。 
看下面的代码:

struct man{    char *name;    void show(){        printf("hello, I'm %s.\n",name);    }};int main(void) {    struct man man1;    man1.name = "wei";    man1.show();    return EXIT_SUCCESS;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

直接编译,我们会得到这样的信息: error: ‘struct man’ has no member named ‘show’ 
而如果是在C++ 中编译,这不会有问题。 
C++ 中的struct是有this指针的,如下代码可以正常运行:

struct man{    char *name;    man(const char *name){        strcpy(this->name,name);    }    void show(){        printf("hello, I'm %s.\n",name);    }};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结构体中的成员默认都是public的。 
结构体不能包含显式的无参构造函数。如:

struct man{    char *name;    man(const char *name){        //strcpy(this->name,name);        this->name = (char *)name;    }    man(){        this->name = "??";    }    void show(){        printf("hello, I'm %s.\n",name);    }};int main(void) {    struct man man2();    man2.show();    return EXIT_SUCCESS;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们将得到:

error: request for member ‘show’ in ‘man2’, which is of non-class typeman()’
  • 1

将man()删除仍然有这样的错误,这是为什么,因为结构体是没有默认的构造函数的,涉及到initobj等指令。

结构从基类OBJECT继承,但它不支持继承。

联合

联合体的存储

联合变量的存储区域可以存储多类型的数据。但是在任何时候,它只能存储一种数据,联合变量的大小是size最大成员的大小。 
下面是一个联合的例子,涉及到C++的typeid操作符,用于判断数据类型。

#include <typeinfo>#include <iostream>#include <stdio.h>using namespace std;union numbers{    char letter;    int number;    float dec_number;    double pre_number;};int main(){    union numbers num;    num.letter = 'a';    printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\            typeid(num.letter).name(),sizeof(num.letter),sizeof(num));    num.number = 1;    printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\            typeid(num.number).name(),sizeof(num.number),sizeof(num));    num.dec_number = 1.0f;    printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\            typeid(num.dec_number).name(),sizeof(num.dec_number),sizeof(num));    num.pre_number = 1.0;    printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\            typeid(num.pre_number).name(),sizeof(num.pre_number),sizeof(num));    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

执行:

# ./a.out typeid return c, out data type size is 1, union numbers size is 8typeid return i, out data type size is 4, union numbers size is 8typeid return f, out data type size is 4, union numbers size is 8typeid return d, out data type size is 8, union numbers size is 8
  • 1
  • 2
  • 3
  • 4
  • 5

联合的嵌套

在联合的定义中可以存在另一种不同的联合类型。比如:

union numbers{    char letter;    int number;    float dec_number;    double pre_number;};union Union{    union numbers num;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

和结构体是一样的,它不能自身嵌套定义,比如:

union Union{    union Union num;};
  • 1
  • 2
  • 3

我们也能定义含有指向自身类型的指针的联合类型。

union Union{    union Union* num;};
  • 1
  • 2
  • 3

在这种情况下,num的类型已经改变,不再是自身。

位字段

首先复习一下字节、位等关键概念。Byte为字节,bit即位。转换 
1B = 8b; 1KB = 1024B; 1MB = 1024KB; 1GB = 1024MB. 
使用位字段,结构的成员被压缩到了一起,允许程序员在位的层次上访问内存,节省存储空间。注:位字段的数据类型必须是(signed) int、unsigned int。同时,位字段类型变量

不能地址操作 //--> error: cannot take address of bit-field ‘field1’   不能计算字节数,sizeof   //error: ‘sizeof’ applied to a bit-field  
  • 1
  • 2

看看这个例子:

#include <stdio.h>#include <stdlib.h>struct temp{    int field1:8;    int field2:16;    long long t;    };int main(){    struct temp num;    //printf("struct temp size is %d, field1 size is %d, field2 size is %d\n",sizeof(struct temp),sizeof(num.field1),sizeof(num.field2));    //void *p = (void *)&num.field1;    printf("struct temp size is %d\n",sizeof(struct temp));    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

编译执行

[root@CentOS workspace]# gcc bit.c [root@CentOS workspace]# ./a.out struct temp size is 12
  • 1
  • 2
  • 3

field1和field2的内存占用是3个字节,int数据类型的字节数是4,所以最终结构体的内存占用是4+8 = 12.

枚举

通过枚举,我们可以定义自己的几种可能值的数据类型。 
在默认的情况下,第一个值和0关联,第二个值和1关联… 
C语言中没有布尔数据类型,我们可以自定义。 
比如:

#include <stdio.h>#include <stdlib.h>enum Boolean {false,true};typedef enum Boolean bool;bool check(int tag){    if(tag&1) return false;    return true;}int main(){    if(check(2)) puts("even");    else puts("odd");       return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果是自定义枚举成员的值,那么未自定义的成员按照顺序增大的原则赋值。比如:

#include <stdio.h>#include <stdlib.h>enum Node{t1=1, t2, t3=5, t4, t5};int main(){    printf("t2 is %d, t4 is %d, t5 is %d\n",t2,t4,t5);    return 0;}/*[root@CentOS workspace]# ./a.out t2 is 2, t4 is 6, t5 is 7*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

值得注意的是,enum的变量可以被任意赋值(不过只能给枚举变量赋值整数哈),不一定是定义的枚举成员。

#include <stdio.h>#include <stdlib.h>enum Node{t1=1, t2, t3=5, t4, t5};int main(){    //printf("t2 is %d, t4 is %d, t5 is %d\n",t2,t4,t5);    enum Node t=-1;    printf("t is %d\n",t);      return 0;}
0 0
原创粉丝点击