typedef (类型别名)

typedef关键字,可以给类型取别名(alias),语法:

typedef 原类型名 新类型名

使用typedef去给函数指针类型取别名,语法略有不同。

typedef void(*PFNTYPE1)(int sig);
typedef void(*PFNTYPE2)(int sig);
PFNTYPE2 mysignal(int sig, PFNTYPE1 func);

善于使用typdef,可以增强代码可读性。

也可以减少重构中修改代码的量。

条件编译

条件编译属于一种预处理命令,它可以根据宏是否定义,来决定某段代码是否要编译。

假设一个场景,我们写的程序,可能在windows和Linux上编译,在Linux上,因为种种原因,不能得到全面的支持。

我们希望按照条件编译,只要一份源码,可以自动的编译出windows和linux对应的版本。

#ifdef ARCH_WIN
/*代码段1*/
int main(int argc, char* argv[])
{ printf("windows, OK"); return 0; }
#else
int main(int argc, char* argv[])
{ printf("Linux, OK"); return 0; }
#endif

以上代码:如果定义了ARCH_WIN这个宏,那么编译代码段1,否则,编译代码段2.

条件编译在工程中的应用非常多。比如我们所谓的Debug版本,和Release版本其实就是条件编译控制的。

我们不仅可以通过define指令去设置宏,还可以通过VS设置宏:

vs设置宏的原理,是直接通过编译器的编译选项设置。所以对于所有的cpp文件全部生效。

条件编译在头文件包含中的应用

赤裸裸的头文件包含,容易产生重复包含的问题。

有些头文件被重复包含了。轻则降低效率,重则编译出错。

我们可以使用条件编译,解决这个问题。

解决方案,是按照以下模板去写头文件:

#ifndef 非常特殊的宏
#define 非常特殊的宏
你的头文件的内容……
#endif

这种套路,被更新的指令

#pragma once

所取代。

结构体

现在,我们开始学习非基本数据类型。非基本数据类型,顾名思义,不是编译器天生

直到的类型。是程序员发明的类型:

  • 程序员先发明新类型(非基本数据类型)
  • 然后再用新类型,去定义新变量

    我们即将学习的结构体(struct),是C语言中最重要的非基本数据类型。

    它的发明目的,是为了复合信息。

    举例,如果我们要写一个学生管理系统,那么当然要保存学生的信息,比如:
  • 姓名, char[12]
  • 性别, int
  • 学号, int

    如果没有到结构体语句的话

    记录一,两个学生的信息还好,当需要记录的学生越来越多时,容易出错。因为姓名、ID、学号没有被很好

    的封装起来。

    结构体,就是为了解决封装问题而诞生的语法。

定义结构体类型

struct tagStudent
{
char szname[8];
int nGender;
int nStuId;
};

使用结构体定义新的结构体变量

纯正c89语法:

struct tagstudent stu1;

之后的C++以及较新的C编译器,都允许省略struct来定义结构体变量

tagstudent stu1;

结构体成员的引用与赋值

从结构体类型的定义就可以看出,结构体中封装了多种变量。

我们可以通过"."运算符,去引用到结构体内部的变量(结构体成员)。

struct tagStudent
{
char szName[8];
int nGender;
int nStuId;
}; int main(int argc, char* argv[])
{ struct tagStudent stu1; strcpy(stu1.szName, "刘x");
stu1.nGender = 1;
stu1.nStuId = 20172519; return 0; }

结构体指针及其引用

如果需要将结构体作为参数传递

强烈不推荐使用值传递的方法传递结构体。

而强烈推荐使用指针传递结构体。

因为以值传递的方式传递结构体,结构体会整体被拷贝到栈帧并随函数返回释放。这常常意味着较大的消耗资源。

甚至可能造成栈帧的崩溃

struct tagStudent
{
char szName[2000000];
int nGender;
int nStuId;
}; void ShowStu(tagStudent stu)
{
printf("姓名:%s, 性别:%d, 学号:%d",
stu.szName,
stu.nGender,
stu.nStuId);
} struct tagStudent g_stu1; int main(int argc, char* argv[])
{ strcpy(g_stu1.szName, "刘x");
g_stu1.nGender = 1;
g_stu1.nStuId = 20172519; ShowStu(g_stu1); return 0; }

综上所述,我们推荐使用地址的方式(结构体指针)传递结构体。

  • 结构体指针的定义:
struct tagStudent
{
char szName[200000];
int nGender;
int nStuId;
}; void ShowStu(tagStudent* pstu)
{
printf("姓名:%s, 性别:%d, 学号:%d",
pstu->szName,
pstu->nGender,
pstu->nStuId); pstu->nGender = 0;
} struct tagStudent g_stu1; int main(int argc, char* argv[])
{ strcpy(g_stu1.szName, "XX");
g_stu1.nGender = 1;
g_stu1.nStuId = 1233456; ShowStu(&g_stu1); return 0; }

C语言中typedef,条件编译,结构体的说明的更多相关文章

  1. C语言中,隐藏结构体的细节

    我们都知道,在C语言中,结构体中的字段都是可以访问的.或者说,在C++ 中,类和结构体的主要区别就是类中成员变量默认为private,而结构体中默认为public.结构体的这一个特性,导致结构体中封装 ...

  2. C语言中FILE是结构体,文件类型的指针

    c语言文件类型指针 我们在定义文件类型指针变量后,称作该指针指向该文件,但本质上,它不是指向一个存储文件信息的结构型变量么?那么我们在用各个函数对所谓的“文件指针”进行操作时,本质上是不是函数通过获取 ...

  3. c语言中,在结构体中如何将void *转存为具体需要的数据类型

    1. 只需要将该void *类型成员,强制转换为具体的数据类型指针即可.需要注意的是,该强制转换是有风险的,转换时,必须确定void*指向内存实际数据为目标结构体格式,否则可能会出现内存越界访问,从而 ...

  4. C语言中typedef用法

    C语言中typedef用法 1. 基本解释 typedef为C语言的关键字,作用是为一种数据类型定义一个新名字.这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等) ...

  5. typedef 定义结构体数组或其他数组

    typedef 定义结构体数组或其他数组 C\C++语言下 typedef其实是对一个变量类型的名字进行重新定义,例如下面中: typedef struct { int num[10]; char n ...

  6. C语言中typedef的解释_2

    typedef工具是一个高级数据特性.利用typedef可以为某一类型自定义一个新的名称.这样可以提高程序的可读性,可移植性,向用户表明特定用途. typedef没有创建任何新的类型,它只是为某个已存 ...

  7. typedef struct 结构体

    typedef struct _TTTT_ {   int    i;  }TT_TT; 定义变量如下: struct _TTTT_  NewTT;方法1 TT_TT NewTT;方法2 是声明和定义 ...

  8. C语言中typedef

    一.基本概念剖析 ])(int, char*); //#1 ]) (void (*)()); //#2 ]; //#3 .C语言中函数声明和数组声明.函数声明一般是这样: int fun(int, d ...

  9. C语言中typedef的解释_1

    typedef是在计算机编程语言中用来为复杂的声明定义简单的别名,它与宏定义有些差异. 它本身是一种存储类的关键字,与auto.extern.mutable.static.register等关键字不能 ...

随机推荐

  1. Win7安装VS2019

    SP1 补丁 WIN7安装VS2019需要更新两个补丁才能顺利安装,否则会闪退. KB4474419 KB4490628 https://zhidao.baidu.com/question/18026 ...

  2. Vue 工程化最佳实践

    目录结构 总览   api 目录用于存放 api 请求,文件名与模型名称基本一致,文件名使用小驼峰,方法名称与后端 restful 控制器一致.   enums 目录存放 常量,与后端的常量目录对应 ...

  3. java+大文件上传解决方案

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...

  4. K8s中RS和Deployment

    什么是ReplicaSet? ReplicaSet是下一代复本控制器.ReplicaSet和 Replication Controller之间的唯一区别是现在的选择器支持.Replication Co ...

  5. sql 用表组织数据

    一.四种完整性约束 1.实体完整性约束:不允许出现相同记录的数据 2.域完整性约束:对字段进行限定,不得插入不符合限定的数据 3.引用完整性:表与表之间的关系 4.自定义完整性约束:开发人员自己设定对 ...

  6. 消费端ACK和重回队列

    使用场景 消费端ACK和重回队列 消费端ACK使用场景: 1.消费端进行消费的时候,如果由于业务异常我们可以进行日志记录,然后进行补偿. 2.由于服务器宕机等严重问题,那我们就需要手工进行ACK保障消 ...

  7. 突破大文件上传 和内网ip的端口转发

    php上传大于2M文件的解决方法 2016年12月11日 :: katelyn9 阅读数 php上传大于2M文件的解决方法 如上传一个文件大于2m往往是上传不成功的解决方法: php.ini里查找 查 ...

  8. PHP AJAX返回 "TEXT"

    例子:通过AJAX间接访问数据库,查出Nation表显示在页面上,并添加删除按钮 //首先在外层添加一个按钮,并造好表头 <div><input type="button& ...

  9. Python: sklearn库——数据预处理

    Python: sklearn库 —— 数据预处理 数据集转换之预处理数据:      将输入的数据转化成机器学习算法可以使用的数据.包含特征提取和标准化.      原因:数据集的标准化(服从均值为 ...

  10. Python学习笔记—Dict和set

    dict Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根据同学的名字 ...