C语言之存储类,枚举,结构体,共用体,typedef

1 存储类

存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C 程序中可用的存储类:
auto,register,static,extern

1.1 auto存储类

auto存储类是所有 局部变量默认的存储类,可以省略

{
   int mount;
   auto int month;
}

上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量。

1.2 register存储类

register 存储类用于定义存储在寄存器中而不是RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个字),且 不能对它应用一元的 '&' 运算符(因为它没有内存位置)

{
   register int  miles;
}

寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 register 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

1.3 static 存储类

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。
因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以
全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。

全局变量和全局静态变量的区别:

  • 全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用全局变量。
    全局变量保存在内存的全局存储区中,占用静态的存储单元
  • 全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用

1.4 extern 存储类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:

第一个文件:main.c

#include <stdio.h>
 
int count ;
extern void write_extern();
 
int main()
{
   count = 5;
   write_extern();
}

第二个文件:support.c

#include <stdio.h>
 
extern int count;
 
void write_extern(void)
{
   printf("count is %d\n", count);
}

在这里,第二个文件中的 extern 关键字用于声明已经在第一个文件 main.c 中定义的 count

2 枚举

2.1 定义

枚举语法定义格式为:

enum 枚举名 {枚举元素1,枚举元素2,……};

示例:

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
可以在定义枚举类型时改变枚举元素的值:enum season {spring, summer=3, autumn, winter};
没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5

我们可以通过以下三种方式来定义枚举变量

  1. 先定义枚举类型,再定义枚举变量
    enum DAY{
    MON=1, TUE, WED, THU, FRI, SAT, SUN
    };
    enum DAY day;
  2. 定义枚举类型的同时定义枚举变量
    enum DAY{
    MON=1, TUE, WED, THU, FRI, SAT, SUN
    } day;
  3. 省略枚举名称,直接定义枚举变量
    enum {
    MON=1, TUE, WED, THU, FRI, SAT, SUN
    } day;

示例如下:

#include <stdio.h>
 
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
 
int main()
{
    enum DAY day;
    day = WED;
    printf("%d",day);
    return 0;
}

2.2 操作枚举

2.2.1 用for循环遍历枚举

在C 语言中,枚举类型是被当做int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历
以下实例使用 for 来遍历枚举的元素:

#include <stdio.h>
 
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main()
{
    // 遍历枚举元素
    for (day = MON; day <= SUN; day++) {
        printf("枚举元素:%d \n", day);
    }
}

没法遍历的例子

enum
{
    ENUM_0,
    ENUM_10 = 10,
    ENUM_11
};

2.2.2 将整数转换为枚举

以下实例将整数转换为枚举:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
 
    enum day
    {
        saturday,
        sunday,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday;
 
    int a = 1;
    enum day weekend;
    weekend = ( enum day ) a;  //类型转换
    //weekend = a; //错误
    printf("weekend:%d",weekend);
    return 0;
}

以上实例输出结果为:
weekend:1

3 结构体

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许 存储不同类型的数据项

结构用于表示一条记录,假设想要跟踪图书馆中书本的动态,可能需要跟踪每本书的下列属性:
Title,Author,Subject,Book ID

3.1 定义结构

为了定义结构,必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;
  • tag:是结构体标签。
  • member-list:是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
  • variable-list:结构变量,定义在结构的末尾,最后一个分号之前,可以指定一个或多个结构变量。下面是声明 Book 结构的方式:
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。以下为实例:

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct 
{
    int a;
    char b;
    double c;
} s1;
 
//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
 
//也可以用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

3.2 操作结构体变量

3.2.1 赋值

和其它类型变量一样,对结构体变量可以在定义时指定初始值。

在向结构体赋值时,有两种方式:

  • 在定义结构体就赋值
    struct Demo{int id;} demo = {1}
  • 定义结构体后在赋值
    定义:struct Demo{int id;}
    赋值:struct Demo demo = {1},不可以先声明struct Demo demo,在向demo赋值
    也可以使用demo.id=1的方式赋值
#include <stdio.h>
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book = {"C 语言", "TEST", "编程语言", 123456};
 
int main()
{
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
    
}
执行输出结果为:

title : C 语言
author: TEST
subject: 编程语言
book_id: 123456

注意:不能直接对book.title赋值,因为title是数组,不能直接操作数组对象,是不可修改的左值,在C语言中可以是左值的:

  • 基本类型的变量:char int float double 型变量
  • 枚举类型变量
  • 数组类型下标成员访问:例如 a[i] = 1
  • 结构类型变量或成员变量
  • 联合类型变量或其成员变量
  • 指针

因此为intbook_id可以直接赋值操作

3.2.2 访问结构成员

为了访问结构的成员,我们使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个英文句号。可以使用 struct 关键字来定义结构类型的变量。下面的实例演示了结构的用法:

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
 
   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 输出 Book1 信息 */
   printf( "Book 1 title : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);
 
   /* 输出 Book2 信息 */
   printf( "Book 2 title : %s\n", Book2.title);
   printf( "Book 2 author : %s\n", Book2.author);
   printf( "Book 2 subject : %s\n", Book2.subject);
   printf( "Book 2 book_id : %d\n", Book2.book_id);
 
   return 0;
}

3.2.3 结构作为函数参数

可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。可以使用上面实例中的方式来访问结构变量:

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
/* 函数声明 */
void printBook( struct Books book );
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
 
   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 输出 Book1 信息 */
   printBook( Book1 );
 
   /* 输出 Book2 信息 */
   printBook( Book2 );
 
   return 0;
}
void printBook( struct Books book )
{
   printf( "Book title : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", book.book_id);
}

3.2.4 指向结构的指针

可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:

struct Books *struct_pointer;

现在,可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:
struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,必须使用 -> 运算符,如下所示:

struct_pointer->title;

让我们使用结构指针来重写上面的实例

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
/* 函数声明 */
void printBook( struct Books *book );
int main( )
{
   struct Books Book1;        /* 声明 Book1,类型为 Books */
   struct Books Book2;        /* 声明 Book2,类型为 Books */
 
   /* Book1 详述 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
 
   /* Book2 详述 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* 通过传 Book1 的地址来输出 Book1 信息 */
   printBook( &Book1 );
 
   /* 通过传 Book2 的地址来输出 Book2 信息 */
   printBook( &Book2 );
 
   return 0;
}
void printBook( struct Books *book )
{
   printf( "Book title : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", book->book_id);
}

3.3 位域

3.3.1 位域声明

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为位域位段

所谓位域是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

例如:用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。

3.3.2 位域的定义和位域变量的说明

位域定义与结构定义相仿,其形式为:

struct 位域结构名 
{
 位域列表
};

其中位域列表的形式为:

type [member_name] : width ;
  • type:只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。
  • member_name:位域的名称。
  • width:位域中位的数量。宽度必须小于或等于指定类型的位宽度,也就是转换为二进制的宽度

3.4 复合字面量和结构(C99)

复合字面量也可用于结构,在只需要临时结构时很好用,也可以传递复合字面量本身和地址。
语法是把类型名放在圆括号中,后面是花括号括起来的初始化列表
可以在复合字面量中使用指定初始化器。
复合字面量定义在所有函数外则有静态存储期,定义在块中有自动存储期。

#define MAXTITL 41
#define MAXAUTL 31
struct book {
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

下面是struct book类型的复合字面量:

(struct book) {"The Idiot", "Fyodor Dostoyevsky", 6.99};

3.5 伸缩型数组成员(C99)

C99新增了伸缩型数组成员,利用这项声明的结构,最后一个数组成员不会立即存在。使用这个数组成员可以编写合适的代码。

声明一个伸缩型数组成员有以下规则:伸缩型数组成员必须是结构的最后一个成员,结构中至少有一个成员,伸缩数组的声明类似于普通数组,不过方括号是空的
C99的意图是希望使用一个指向此结构的指针,然后用malloc()动态内存分配足够的空间来存储数据。

#include<stdio.h>
#include<stdlib.h>
struct flex
{
    size_t count;
    double average;
    double scores[];
};
void showFlex(struct flex* p);
 
int main(void)
{
    struct flex* pf1, * pf2;
    int n = 5;
    int i;
    int tot = 0;
    pf1 = malloc(sizeof(struct flex) + n * sizeof(double));
    pf1->count = n;
 
    for (i = 0; i < 5; i++) {
        pf1->scores[i] = 20.0 - i;
        tot += pf1->scores[i];
    }
    pf1->average = tot / n;
    showFlex(pf1);
    
    n = 9;
    tot = 0;
    pf2 = malloc(sizeof(struct flex) + n * sizeof(double));
    pf2->count = n;
 
    for (i = 0; i < n; i++) {
        pf2->scores[i] = 20.0 - i / 2.0;
        tot += pf2->scores[i];
    }
    pf2->average = tot / n;
    showFlex(pf2);
 
    free(pf1);
    free(pf2);
    return 0;
}
void showFlex(struct flex* p)
{
    int i;
    printf("Score : ");
    for (i = 0; i < p->count; i++)
        printf("%g ", p->scores[i]);
    printf("\nAverage:%g\n", p->average);
}

有伸缩型数组成员的结构有一些特殊处理要求:不能用结构进行赋值或拷贝,不能按值传递给函数,不要作为一个数组的成员或另一个结构的成员。

3.6 匿名结构(C11)

匿名结构是一个没有名称的结构成员,在一个结构体声明中用一个复合字面量声明另一种结构。
这样初始化的方式相同,但是访问被嵌套的成员时简化了步骤(少用一次)

#include <stdio.h>
#include <string.h>

struct Student{
    char name[20]; //姓名
    short gender; //性别
    //struct conact; //匿名结构作为Student成员
    struct{ //匿名结构
        char email[30]; //邮箱
        long long phone; //电话号码        
    };
};
int main(){
    struct Student st1;
    strcpy(st1.name, "李小花");
    st1.gender = 2;
    strcpy(st1.email, "lixiaohua@163.com");
    st1.phone = 13001300123;
    
    printf("姓名:%s\t性别:%hd\t%邮箱:%s\t电话:%lld\n", st1.name, st1.gender, st1.email, st1.phone);
    
    return 0;
}

4 共用体

共用体是一种特殊的数据类型,允许我们在相同的内存位置存储不同的数据类型。可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种 使用相同的内存位置的有效方式

4.1 定义共用体

为了定义共用体,必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:

union [union tag]
{
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];

union tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,可以指定一个或多个共用体变量,这是可选的。下面定义一个名为 Data 的共用体类型,有三个成员 i、f 和 str:

union Data
{
   int i;
   float f;
   char  str[20];
} data;

现在,Data类型的变量可以存储一个整数、一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。

共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的总内存大小:

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
   printf( "Memory size occupied by data : %d\n", sizeof(data)); 
   return 0;
}

结果:
Memory size occupied by data : 20

4.2 初始化共用体

  • 声明同时定义
union tel_email //电话或邮箱
{
    int tel;
    char *email;
}contactInfo;//联系方式
  • 先声明,后定义
//声明共用体类型
union tel_email
{
    int tel;
    char *email;
};

//定义共用体变量
union tel_email contactInfo;

注意:共用体变量不可以在定义的同时初始化,因此不能像初始化结构体那样直接使用大括号初始化

contactInfo.email="kinglake_w@163.com";
printf("%s\n\n",contactInfo.email);

4.3 操作共用体

4.3.1 访问共用体成员

为了访问共用体的成员,我们使用成员访问运算符(.)
成员访问运算符是共用体变量名称和我们要访问的共用体成员之间的一个英文句号。可以使用 union 关键字来定义共用体类型的变量。

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");
 
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

结果:
data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

在这里,我们可以看到共用体的 i 和 f 成员的值有损坏,因为最后赋给变量的值占用了内存位置,这也是 str 成员能够完好输出的原因。现在让我们再来看一个相同的实例,这次我们在同一时间只使用一个变量,这也演示了使用共用体的主要目的:

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   data.i = 10;
   printf( "data.i : %d\n", data.i);
   
   data.f = 220.5;
   printf( "data.f : %f\n", data.f);
   
   strcpy( data.str, "C Programming");
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

结果:
data.i : 10
data.f : 220.500000
data.str : C Programming

在这里,所有的成员都能完好输出,因为同一时间只用到一个成员。

4.4 匿名共用体(C11)

匿名共用体(anonymous union)没有名称,其成员将成为位于相同地址处的变量。
如果我们将一个 union 包括在一个结构(structure)的定义中,并且不赋予它对象(object)名称 (就是跟在花括号{}后面的名字),这个union 就是匿名的。这种情况下我们可以直接使用 union 中元素的名字来访问该元素,而不需要再在前面加 union 对象的名称。

在下面的例子中,我们可以看到这两种表达方式在使用上的区别:


8ac7c10c3ef21676851d97c89e8a60d4_4c0bb2ca7048474cae1040bd3564a987.png

以上两种定义的唯一区别在于左边的定义中我们给了 union 一个名字 price ,而在右边的定义中我们没给。
在使用时的区别是当我们想访问一个对象(object)的元素 dollars 和 yen 时,在前一种定义的情况下,需要使用:book.price.dollars; 和 book.price.yen;,而在后面一种定义下,我们直接使用:book.dollars;和book.yen;
再一次提醒,因为这是一个联合(union),域 dollars 和 yen 占据的是同一块内存空间,所以它们不能被用来存储两个不同的值。也就是你可以使用一个 dollars 或 yen 的价格,但不能同时使用两者。

4.5 与结构体差异

与结构体差异:

  • 内存大小差异:
    • 结构体变量所占内存长度是其中最大字段大小的整数倍
    • 共用体变量所占的内存长度等于最长的成员变量的长度。例如,共用体Data各占20个字节(因为char str[20]变量占20个字节),而不是各占4+4+20=28个字节
  • 存储影响:
    • 结构体的各个成员会占用不同的内存,互相之间没有影响
    • 共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员

共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉

示例如下:

#include <stdio.h>
struct StructName{
    int a;
    float b;
    char c;
};
union UnionName{
    int a;
    float b;
    char c;
};
void main() 
{
    printf("测试====\n\n");
    int sizeStruct = sizeof(struct StructName);
    int sizeUnion = sizeof(union UnionName);
    printf("sizeStruct = %d, sizeUnion = %d\n", sizeStruct, sizeUnion);
    printf("\n");
    return 0;
}

5 typedef

5.1 简介

C 语言提供了 typedef 关键字,可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE

typedef unsigned char BYTE;

在这个类型定义之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:

BYTE b1, b2;

按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但也可以使用小写字母,如下:

typedef unsigned char byte;

5.2 使用

也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。
例如,可以对结构体使用 typedef 来定义一个新的数据类型名字,然后使用这个新的数据类型来直接定义结构变量,如下:

#include <stdio.h>
#include <string.h>
 
typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Book;
 
int main( )
{
   Book book;
 
   strcpy( book.title, "C 教程");
   strcpy( book.author, "Test"); 
   strcpy( book.subject, "编程语言");
   book.book_id = 12345;
 
   printf( "书标题 : %s\n", book.title);
   printf( "书作者 : %s\n", book.author);
   printf( "书类目 : %s\n", book.subject);
   printf( "书 ID : %d\n", book.book_id);
 
   return 0;
}

结果:
书标题 : C 教程
书作者 : Test
书类目 : 编程语言
书 ID : 12345

5.3 typedef vs #define

#define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:

  • typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如可以定义 1 为 ONE。
  • typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

  • 前四节,我们从编写一个计算器的角度,讨论出编程语言需要数据类型、变量和常量,并详细介绍了这三个概念。那么编写一个计...
    流光月痕阅读 274评论 0 1
  • C 变量 变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,...
    苏州丸子阅读 1,031评论 0 0
  • 2019年3月12日星期二 晴emmmmm,昨天在赶报告所以又木有更新,今天还是要继续啊! (声明:理论知识部分来...
    竹予青青阅读 200评论 0 3
  • C 存储类 存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面...
    有缺_z阅读 131评论 0 0
  • 存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C 程...
    快乐舔狗董枭垚阅读 304评论 0 0