结构体struct、枚举enum、联合体union、位字段、自定义类型typedef、字节对齐

1.结构体struct

1.1 结构体的基本知识

#include <stdio.h>

struct point{
        int x;
        int y;
}p1, p2, p3;
struct point pt;
struct point pt2 = {300, 400};
struct point pt3 = {.x = 500};

struct rect {
        struct point pt1;
        struct point pt2;
};
struct rect screen;

int main()
{
        printf("pt2.x = %d, pt2.y = %d\n", pt2.x, pt2.y);
        printf("pt3.x = %d, pt3.y = %d\n", pt3.x, pt3.y);

        double dist, sqrt();
        dist = sqrt((double)pt2.x*pt2.x + (double)pt2.y*pt2.y);
        printf("dist = %lf \n", dist);

        printf("screen.pt2.x = %d \n", screen.pt2.x);

        return 0;
}
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim struct.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc struct.c 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
pt2.x = 300, pt2.y = 400
pt3.x = 500, pt3.y = 0
dist = 500.000000 
screen.pt2.x = 0 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ 

1.2 结构体与函数

  • 传递结构体的每个成员变量;
  • 传递整个机构体;
  • 传递指向结构体的指针;
#include <stdio.h>

struct point{int x; int y;};
struct rect {
        struct point pt1;
        struct point pt2;
};

struct rect screen;
struct point midlle;
struct point makepoint(int, int);

int main()
{
        #define XMAX 300
        #define YMAX 400
        screen.pt1 = makepoint(0, 0);
        screen.pt2 = makepoint(XMAX, YMAX);

        struct point origin = {30}, *pp;
        origin.y = 40;
        //origin = {.x = 30, .y = 40}; //error
        //origin = {30, 40}; //error
        pp = &origin;
        printf("origin: .x,.y is (%d, %d)\n", origin.x, origin.y);
        printf("origin: (*pp).x is (%d, %d)\n", (*pp).x, (*pp).y);
        printf("origin: pp->x   is (%d, %d)\n\n", pp->x, pp->y);

        return 0;
}

struct point makepoint(int x, int y)
{
        struct point temp;

        temp.x = x;
        temp.y = y;
        return temp;
}
/*
struct point addpoint(struct point p1, struct point p2)
{
        p1.x += p2.x;
        p1.y += p2.y;
        return p1;
}

int pt_in_rect(struct point p, struct rect r)
{
        return p.x >= r.pt1.x && p.x <= r.pt2.x
            && p.y >= r.pt1.y && p.y <= r.pt2.y;
}

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
// 矩形规范化
struct rect canon_rect(struct rect r)
{
        struct rect temp;

        temp.pt1.x = min(r.pt1.x, r.pt2.x);
        temp.pt1.y = min(r.pt1.y, r.pt2.y);
        temp.pt2.x = max(r.pt1.x, r.pt2.x);
        temp.pt2.y = max(r.pt1.y, r.pt2.y);
        return temp;
}
*/
struct  rect r, *rp = &r;
//下面四个等价的
r.pt1.x;
rp->pt1.x;
(r.pt1).x;
(rp->pt1).x;
//anonymous struct
struct {int len; char * str; }*p, pn[]={{10,"ah",},20,"ABC", 30,"123",};
p = &pn; //struct3.c:7:3: warning: incompatible pointer types assigning to 'struct (anonymous struct at struct3.c:6:1) *' from 'struct (anonymous struct at struct3.c:6:1) (*)[3]' [-Wincompatible-pointer-types]
p = pn;

//下面两个等价的
++p->len;   //11
++(p->len); //12

//指向下个对象
(++p)->len; //20
(p++)->len; //20
(p)->len;   //30

//字符串的操作
p = pn;
*p->str 同 *(p->str) // just a char. %c: a
*p->str++ 同 *s++    // %c: a ,->h
//(*p->str)++ 对象++,导致段错误
(*p->str)+1 //i
*p->str + 2 //j
*p++->str //%c: h 先取str值,后指向下个对象
*p->str   //%c: A
 p->str   //%s: ABC
++(p->str)//%s: BC

1.3 结构体数组

struct key{
    char *word;
    int count;
}keytab[NKEYS];
struct key keytab2[MKEYS];

struct key{
    char *word;
    int count;
}keytab[]={"AUTO", 0, "char", 2, {"cha", 3,},};

1.4 自引用结构体

struct tnode{
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
};

2.枚举变量enum

例子1

#include <stdio.h>

int main()
{
        enum boolean{NO, YES}b;
        enum boolean bb = YES;
        printf("enum NO: %d\n", NO);
        printf("boolean b: %d \n",b);
        printf("boolena b = %d, bb = %d \n",b = NO, ++bb);
        printf("sizeof(b): %lu, sizeof(enum boolean): %lu \n", sizeof(b), sizeof(enum boolean));
        return 0;
}
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim enum.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc enum.c 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
enum NO: 0
boolean b: 1790791734 
boolena b = 0, bb = 2 
sizeof(b): 4, sizeof(enum boolean): 4 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ 

例子2

// 不同枚举中的名字必须互不相同(有区分大小写),同一枚举不同名字的值可以相同
enum escapes{
    BELL = '\a',
    BELL2= '\a',
    BACKSPACE = '\b',
    TAB = '\t',
    tab = '\t',
    NEWLINE = '\n',
    VTAB = '\v',
    RETURN = '\r',
};

例子3

// 比#define有优势就是常量值就自动生成的,如:FEB = 2, MAR = 3 ...
enum months{JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV ,DEC }; 

3.联合体union

例子1

#include <stdio.h>

//共享同一内存,大小取决于最大成员
union {
        int a;
        char c;
}u = {10}; //初始化第一个成员,而且只能初始化一个

int main()
{
        printf("1 sizeof(u): %lu\n", sizeof(u));
        printf("%d, %c\n", u.a, u.c);

        u.c = 'a';
        printf("2 sizeof(u): %lu\n", sizeof(u));
        printf("%d, %c\n", u.a, u.c);

        return 0;
}
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
1 sizeof(u): 4
10, 

2 sizeof(u): 4
97, a

好处:不确定类型时,或者兼容多种类型。

union u_tag{
    int ival;
    float fval;
    char *sval;
}u;

if(utype == INT){
    printf("%d\n", u.ival);
}else if(utype == FLOAT){
    printf("%f\n", u.fval);
}else if(utype == STRING){
    printf("%s\n", u.sval);
}else{
    printf("bad type %d in utype\n", utype);
}

嵌套在结构体

struct {
    char *name;
    int flags;
    int utype;
    union{
        int ival;
        float fval;
        char *sval;
    }u;
}symtab[NSYM];

//引用成员ival
symtab[i].u.ival;
//引用sval第一个字符
*symtab[i].u.sval;
symtab[i].u.sval[0];

例子2

#include <stdio.h>

union {
        int a;
        float b;
        char c;
}u = {10};

int main()
{
        printf("1 sizeof(u): %lu\n", sizeof(u));
        printf("%d, %f, %c\n", u.a, u.b, u.c);

        u.b = 3.5f;
        printf("2 sizeof(u): %lu\n", sizeof(u));
        printf("%d, %f, %c\n", u.a, u.b, u.c);

        return 0;
}

huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
1 sizeof(u): 4
10, 0.000000, 

2 sizeof(u): 4
1080033280, 3.500000, 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ 

例子2-2


printf("1 sizeof(u): %lu\n", sizeof(u));
printf("%d, %f, %c\n", u.a, u.b, u.c);

u.b = 3.5f;
printf("2 sizeof(u): %lu\n", sizeof(u));
printf("%d, %f, %c\n", u.a, u.b, u.c);

u.c = 'a';
printf("3 sizeof(u): %lu\n", sizeof(u));
printf("%d, %f, %c\n", u.a, u.b, u.c);
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
1 sizeof(u): 4
10, 0.000000, 

2 sizeof(u): 4
1080033280, 3.500000, 
3 sizeof(u): 4
1080033377, 3.500023, a

例子2-3

printf("1 sizeof(u): %lu\n", sizeof(u));
printf("%d, %f, %c\n", u.a, u.b, u.c);

u.c = 'a';
printf("3 sizeof(u): %lu\n", sizeof(u));
printf("%d, %f, %c\n", u.a, u.b, u.c);
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim union.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc union.c 
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
1 sizeof(u): 4
10, 0.000000, 

2 sizeof(u): 4
10, 0.000000, 

3 sizeof(u): 4
97, 0.000000, a
huashidazhongbeitushuguan5deiMac:wufile duzhe$ 

4.位字段

4.1 一般的方法定义屏蔽吗

//宏定义
#define KEYWORD     01
#define EXTERNAL    02
#define STATIC     04

//枚举变量
enum{KEYWORD = 01, EXTERNAL = 02, STATIC = 04};

flags |= EXTERNAL | STATIC;
flags &= ~(EXTERNAL | STATIC);
if((flags & (EXTERNAL|STATIC) ) == 0)...

4.2 用位字段来定义屏蔽吗

unsigned int 最大是4字节*8位 = 32位,sizeof是总的字节数,且为4的倍数(0,4,8,16…).

#include <stdio.h>

//定义了3个一位宽度的字段
struct{ //33 = 32 + 1 (bit)= 4 up byte = 8 type.
    unsigned int is_keyword     : 1;
    unsigned int is_extern      : 1;
    unsigned int is_static      : 1;
    unsigned int err : 8;
    unsigned int add :16;
    //unsigned int err2 :64; //bit.c:10:18: error: width of bit-field 'err2' (64 bits) exceeds width of its type (32 bits)
    int :1;     //无名字段
    int :4;
    int :0;
    int :1;
}flags, *p = &flags;//字段不是数组,没有地址,不能用&引用,但结构体有地址可以用&引用。

int main()
{
        printf("sizeof(flags): %lu\n", sizeof(flags));

        printf("%d, %d\n", flags.is_extern, flags.is_static);
        flags.is_extern = flags.is_static = 0;
        printf("%d, %d\n", flags.is_extern, flags.is_static);
        flags.is_extern = flags.is_static = 1;
        printf("%d, %d\n", flags.is_extern, flags.is_static);
        flags.is_extern = flags.is_static = 2;
        printf("%d, %d\n", flags.is_extern, flags.is_static);
        flags.is_extern = flags.is_static = 3;
        printf("%d, %d\n", flags.is_extern, flags.is_static);

        if(flags.is_extern == 0 && flags.is_static == 0);//...;

        flags.add = 65525;
        flags.err = 255;

        printf("sizeof(flags): %lu\n", sizeof(flags));
        return 0;
}
huashidazhongbeitushuguan5deiMac:wufile duzhe$ vim bit.c
huashidazhongbeitushuguan5deiMac:wufile duzhe$ gcc bit.c  
bit.c:25:43: warning: implicit truncation from 'int' to bitfield changes value from 2 to 0 [-Wbitfield-constant-conversion]
        flags.is_extern = flags.is_static = 2;
                                          ^ ~
bit.c:27:43: warning: implicit truncation from 'int' to bitfield changes value from 3 to 1 [-Wbitfield-constant-conversion]
        flags.is_extern = flags.is_static = 3;
                                          ^ ~
bit.c:30:50: warning: if statement has empty body [-Wempty-body]
        if(flags.is_extern == 0 && flags.is_static == 0);//...;
                                                        ^
bit.c:30:50: note: put the semicolon on a separate line to silence this warning
3 warnings generated.
huashidazhongbeitushuguan5deiMac:wufile duzhe$ ./a.out 
sizeof(flags): 8
0, 0
0, 0
1, 1
0, 0
1, 1
sizeof(flags): 8
huashidazhongbeitushuguan5deiMac:wufile duzhe$ 

5.自定义类型typedef

  • 可移植性
  • 容易理解
typedef int Length;
Length len, maxlen;
Lenght *length[];
typedef char* String;
String p, lineptr[MAXLINES], alloc(int);
int strcmp(String, String);
p = (String) malloc(1024);
typedef struct tnode *Treeptr;
typedef struct tnode{
    char *word;
    int count;
    Treeptr *left;
    Treeptr *right;
}Treenode;

Treeptr talloc(void)
{
    return (Treeptr)malloc(sizeof(Treenode));
}
// PFI是一个指向函数的指针
typedef int (*PFI)(char*, char*);
PFI strcmp, strcpy;

6.字节对齐

以最长(系统一次读的长度)为基本单位。

struct A{
    int   a;//4/
    char  b;//1
    short c;//2
            //1/
}a;
sizeof(a) = sizeof(struct A) = 8;

struct B{
    char  a;//4
    int   b;//4/
    short c;//4
}b;
sizeof(b) = sizeof(struct B) = 12;

32位系统一次4字节,long long 8位读两次。sizeof是以%d: int 返回。

{char 4, LL 4+4, int 4} = 16
{char 4, int 4, short4} = 12
{LL 4+4, char 4, int 4} = 16
{LL 4+4, char 4 short } = 12

64位系统一次8字节,没long时,一次读4字节。sizeof是以%lu: long unsigned int 返回。LL和L都是8个字节。

//一次读8字节
{ LL 8 , char  8  int } = 16
{char 8, LL 8 , int 8 } = 24
//一次读4字节
{char 4,int 4, short 4} = 12
{char 4 short , int 4 } = 8

pragma pach(x) 按x个字节对齐

#pragma pach(2)
struct c{char 2; int 2+2; short 2;} = 8
#pragma pach(1)
struct c{char 1; int 4; short 2;} = 7

Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《结构体struct、枚举enum、联合体union、位字段、自定义类型typedef、字节对齐》: http://blog.csdn.net/u014134180/article/details/78335328

结构体struct、枚举enum、联合体union、位字段、自定义类型typedef、字节对齐

如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。

上一篇:如何通过 Cgroups 机制实现资源限制


下一篇:勒索病毒WannaCry还没搞定 比它更厉害的永恒之石又来了