c++ define,typedef,using

define

#define 是宏定义命令,宏定义就是将一个标识符定义为一个字符串,源程序中的该标识符均以指定的字符串来代替,是预编译命令,因此会在预编译阶段被执行

  • 无参宏定义的一般形式为:
#define  标识符  字符串

“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。

flag    被定义为了 1
#define flag 1
flag    被定义为了 1;
#define flag 1;
  • 有参宏定义

C++语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。
对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参宏定义的一般形式为:

#define  宏名(形参表)  字符串
#define add(x,y) (x+y
  • 宏定义中的条件编译

在大规模的开发过程中,头文件很容易发生嵌套包含,可以使用#ifndef 配合 #define ,#endif ,和#pragma once 作用类似,都是为了防止多次编译一个头文件

#ifndef DATATYPE_H
#define DATATYPE_H

 int a = 0;
#endif
  • 跨平台

跨平台和系统的软件里,可以在编译的时候通过#define设置编译环境

#ifdef WINDOWS
......
(#else)
......
#endif
#ifdef LINUX
......
(#else)
......
#endif
  • 宏定义中的特殊操作符

_FILE_ 宏在预编译时会替换成当前的源文件cpp名
_LINE__宏在预编译时会替换成当前的行号
_FUNCTION__宏在预编译时会替换成当前的函数名称
_DATE
:进行预处理的日期(“Mmm dd yyyy”形式的字符串文字)
_TIME
:源文件编译时间,格式微“hh:mm:ss”

typedef

C 语言提供了 typedef 关键字,为现有类型创建一个新的名字

  • 类型替换
typedef unsigned char   UBYTE;

定义之后,标识符 UBYTE 可作为类型 unsigned char 的缩写
按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,但也可以使用小写字母。

  • 结构体&自定类型义替换

可以使用 typedef 来为自定义的数据类型取一个新的名字

typedef struct Book
{
   char  title[50];
   char  author[50];
} Book;
  • 函数指针

指针函数与函数指针

1)指针函数

指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针

类型标识   *函数名(参数表)
int *getptr(int x);                  //声明一个参数为int , 返回值为int * 的 指针函数

指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量

double *getptr(double x) //声明同时定义一个返回值为double* 的指针函数
{
	return &x;
};

int main()
{
	double *p;
	p = getptr(7); //返回double* 赋给p
	return 0;
}

2)函数指针

函数指针是指向函数地址的指针变量,它的本质是一个指针变量,函数也是有分配内存的,所以指向函数地址的指针,即为函数指针

类型说明符 (*变量名)(参数)
int (*funp)  (int x);                          // 声明一个 指向参数类型为 int ,返回类型为 int 的函数 的 指针
int *(*funp)  (int x);                          // 声明一个 指向参数类型为 int ,返回类型为 int* 的函数 的 指针

变量名为funp,而funp左边有个*,代表funp是指针类型,这个很关键,这个是修饰funp本身的,代表funp是指针类型,至于具体是什么指针类型(是int?,char?,还是函数?)要结合整个表达式看,然后再看右边有括号,说明是个函数,这个函数的参数类型为int,既funp是一个指向函数的指针,再看最左边的int,那就说明func是一个指向参数类型为int,返回值为int的函数 的指针。
那么int *(funp) (int x);funp是一个指向参数类型为int,返回值为int的函数 的指针

“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完
int (*func)(int *p);

首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int类型的形参,返回值类型是int

再比如:

int (*func[5])(int *);

看到数组了,所以func是一个数组呢还是一个指针呢?先别着急,不妨回顾下数组的定义

int a[10] ; //声明一个int型数组a,a有10个元素 , 这个很简单吧,在进一步
int a[10] ; //声明一个int型数组a,a有10个元素

所以这里可以看出来在 int *a[10] ; 中,a[10]是一个整体,是修饰a[10]的,而不是修饰a的,如果修饰a,那么a就是一个指针了,但实际上a是数组,所以是修饰a[10]的,意味着a[10]这个数组中的元素类型为指针。这是C++决定的,[]的优先级较高,把a[]当成一个整体来看,也就是说在类似数组的定义中,如:
类型 变量名[数量n]; 类型是用来表示数组元素的,而变量名也就是a本身是一个数组。

数组指针(也称行指针)
定义格式如下:
类型 (*变量名)[数量n];
int (*p)[5];

因为()优先级高,所以(*p)代表p是一个指针,指向一个int型的一维数组,这个一维数组的长度是5,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。所以 int (*p)[5]; 的含义是定义一个数组指针,指向含5个元素的一维int型数组。

如要将二维数组赋给一指针,应这样赋值:
int a[3][4]; //定义一个二维int型数组
int (*p)[4]; //定义一个数组指针,指向含4个元素的一维int数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

所以数组指针也称指向一维数组的指针,亦称行指针

回到上面讨论的int (*func[5])(int *);
再来对比
int a[10] ; //a是一个数组,数组元素类型为int型指针
int (*func[5])(int ); //func是一个数组,数组元素类型是什么? 看到应该知道了是指针类型,所以答案应该是某某类型的指针,什么类型的指针呢?

再看完整的右左法则”解析:
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比高,func先跟[]结合,把func[]看成一个整体)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int.

所以在分析复制的声明时,优先级很关键()比较高,其次是[],再然后是*

用typedef来定义这些复杂的类型,比如上面的函数指针,格式为:

typedef  返回类型  (*新类型名)  (参数表)
typedef  int  (*PTRFUN)  (int);
typedef char(*PTRFUN)(int); //定义char(*)(int)的函数指针 的别名为PTRFUN
PTRFUN pfun;  //直接用别名PTRFUN定义char(*)(int)类型的变量

char getchar(int a) //定义一个形参为int,返回值为char的函数
{
	return '1';
}
int main()
{
	pfun = getchar; //把函数赋给指针
	(*pfun)(5);     //用函数指针取函数,调用
	return 0;
}

using

  • 声明命名空间
using namespace std;
  • 给类型取别名
using 别名 = 原先类型;
using ty=  unsigned char;
  • 与typedef的区别

typedef,std::unique_ptr<std::unordered_map<std::string, std::string>>

typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;

using

using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;

函数指针不同:

typedef void (*FP) (int, const std::string&);

不是特别熟悉函数指针与typedef的,还是很难指出FP其实是一个别名,代表着的是一个函数指针,而指向的这个函数返回类型是void,接受参数是int, const std::string&。使用using的话,就比较清晰

using FP = void (*) (int, const std::string&);
typedef std::string (Foo::* fooMemFnPtr) (const std::string&);

using fooMemFnPtr = std::string (Foo::*) (const std::string&);

typedef做不到,而using可以做到的例子:alias templates, 模板别名

template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;

// usage
Vec<int> vec;

若使用typedef来做这一切:

template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;

// usage
Vec<int> vec;

使用编译器编译的时候,将会得到类似:error: a typedef cannot be a template的错误信息。如果想要用typedef做到这一点,那就是包装一层

template <typename T>
struct Vec
{
  typedef MyVector<T, MyAlloc<T>> type;
};

// usage
Vec<int>::type vec;

如果你想要把这样的类型用在模板类或者进行参数传递的时候,需要使用typename强制指定这样的成员为类型,而不是说这样的::type是一个静态成员亦或者其它情况可以满足这样的语法,如:

template <typename T>
class Widget
{
  typename Vec<T>::type vec;
};

如果是使用using语法的模板别名,你则完全避免了因为::type引起的问题,也就完全不需要typename来指定了。

// if we use using syntax.
template <typename T>
class Widget
{
  Vec<T> vec;
};

一切都会非常的自然,所以于此,非常推荐using,而非typedef。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值