关于#define、typedef、using(C++11)

一、#define

在题主的例子的这种用法里, 它就是个文本替换工具, 预处理器完成的, 无脑替换, 跟word里的replace一模一样, 不关编译器的事. 只需要注意下面几点:

1.宏定义

#是宏,处理的时候位于编译前阶段,宏处理器基本上对你的C/C++程序不会有任何的感知。它只处理宏的语法。而编译阶段的“程序”得到的是宏处理完的结果。#define 没有参加编译,在预处理的时候就被替换掉了。

当替换列表中含有多个字符的时候,最好的将替换列表用圆括号括起来。也可以定义一些简单的函数,但因为只是简单的替换,有时候会发生一些错误,谨慎使用,在替换列表中的各个参数最好使用圆括号括起来。

#define maxnum  1000
#define add(a,b) (a+b) //此处要打括号,不然执行A*add(a,b)*C 会变成 A*a+b*C

3.条件编译

通过#define  (windows、debug),可以选择需要编译的代码,这在跨平台或者调试的时候有很好的帮助。

#ifdef  windows
...
#else
...
#endif
#ifdef debug
...
...
#endif

4、文件包含

在引入头文件的过程中,由于头文件往往会互相包含,因此容易出现重复包含定义的问题。

#ifndef _HEADFILE_
#define _HEADFILE_
...
...
#endif

需要注意的是:宏定义 是字符串的置换替代,当参数是表达式或带有负号时会引入2义性,所以要多用括号。

#include "stdio.h"
#define SQR(x) x*x

int main()
{
	int a, k =3;
	a = SQR(k + 1);      //k+1*k+1=2k+1
        a = ++SQR(k + 1);    //++k+1*k+1=4+1*4+1
	printf("%d\n", a);
}

 

二、typedef

typedef是编译阶段的一部分,参加编译和链接。它的意义是单一的。

Bjarne Stroustrup在其著作的《the design and evolution of c++》中有一个关于typedef的小例子

typedef int P();
typedef int Q();
class X {
    static P(Q); // 将Q定义为P,等价于static int Q(), Q周围的括号是多余的
                
                 // Q不再是一个类型而变成了一个函数

    static Q(P); // 将Q定义为函数,采用P类型的论证方式
                 // 返回值为int,等价于static int Q(int ())
};

解释将在后面第一点提出。

这是一个极好的例子, 先问一下 typedef int P()到底做了什么? 其实是:

declares a function type P as returning an int and taking no arguments.                                                                                  将函数类型P声明为int型返回,并且不带参数。

 我们再来看下书中对其的定义

Typedef does not work like typedef [type] [new name]. The [new name] part does not always come at the end.   Typedef不像 typedef [type] [new name]那样工作。 [new name]部分并不总是在最后。

You should look at it this way: if [some declaration] declares a variable, typedef [same declaration] would define a type.  你应该这样看:如果[some declaration]声明一个变量,typedef [same declaration]会定义一个类型。

看我标黑的这句话, 总结一下就是: 任何声明变量的语句前面加上typedef之后,原来是变量的都变成一种类型不管这个声明中的标识符号出现在中间还是最后

 

然后,我们需要了解需要理解『模板』和『类型』之间的不同。仔细体会这句话:模板是用来产生类型的。在传统 C++中,typedef 可以为类型定义一个新的名称,但是却没有办法为模板定义一个新的名称。因为,模板不是类型。例如:

template< typename T, typename U, int value>
class SuckType {
public:
    T a;
    U b;
    SuckType():a(value),b(value){}
};
template< typename U>
typedef SuckType<std::vector<int>, U, 1> NewType; // 不合法

而C++11 使用 using 引入了下面这种形式的写法,并且同时支持对传统 typedef 相同的功效,我们下面再说。

回到typedef,我们先简单看个例子理解下它的好处:

 

更多小知识:

1.typedef 定义的新类型, 使用时可以省略括号。 

typedef int NUM;
NUM a = 10; // 也可写成`NUM(a) = 10;`
NUM(b) = 12; // 也可写成`NUM b = 12;`

现在回过头看: 

typedef int P();
static P(Q); 

P是一个新定义的function类型, 它返回值为int, 无参数; P(Q)实际上等价于P Q, 声明Q是一个返回值为int, 无参数的函数.

 

2.使用

typedef int x; // 定义了一个名为x的int类型
typedef int *p; //定义了一个名为p的指针类型, 它指向int
typedef struct{char c;} s; // 定义名为s的struct结构体类型
typedef class{private: int x; public: int y;} MyClass;  //类类型


//下面这些的标识符不一定放在最后
typedef int A[];  // 定义一个名为A的ints数组的类型
typedef int f(); // 定义一个名为f, 参数为空, 返回值为int的函数类型
typedef int g(int); // 定义一个名为g, 含一个int参数, 返回值为int行的函数类型

这玩意有什么用呢?
我们都知道C++语言里, 函数都是先声明后使用的(除非在使用之前定义), 看以下例子:

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

typedef int P(); // 简单的
typedef void Q(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true); // 复杂的

class X {
public:
	P(eat_shit); // 等价于声明`int eat_shit();`
	Q(bullshit); // 等价于声明`void bullshit(int *p, const string& s1, const string& s2, size_t size, bool is_true);`
};

int main() {
	X *xx;
	std::cout <<"shit ret:"<< xx->eat_shit() << std::endl;
	int a[] = { 1, 3, 4, 5, 7 };
	xx->bullshit(a, "foo", "bar", sizeof(a) / sizeof(int), true);

	system("pause");
	return 0;
}

int X::eat_shit() {
	return 888;
}

void X::bullshit(int *p, const std::string& s1, const std::string& s2, size_t size, bool is_true) {
	std::cout << "s1: " << s1 << ", s2: " << s2 << ", size: " << size << std::endl;
	std::cout << "elems:" << std::endl;
	for (int i = 0; i < size; i++) {
		std::cout << *p++, (i == size - 1) ? "" : ",";
	}
	std::cout << std::endl;
}

 

三、using 

另外,在 C++11 标准中,引入了新的为类型取别名的关键字 using,可以用来代替 typedef, 而且更好理解:

typedef int (*process)(void *);  // 定义了一个返回类型为 int,参数为 void* 的函数指针类型,名字叫做 process
using process = int(*)(void *); // 同上, 更加直观

template <typename T>
using NewType = SuckType<int, T, 1>;    // 合法
using iArr = int [6];
using pNode = Node *;
using pfunc = int (*) (int a, int b);

从可读性上 using 好于 typedef 。此外 typedef 和 using 不是完全等价的,using 可以用来 给模板取别买,typdef 则不行。

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

// usage
Vec<int> ivec;

用起来非常自然。若是使用 typedef,则是这样:

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

// usage
Vec<int> vec;

编译的时候,会得到类似 error: a typedef cannot be a template 的错误信息。

总结起来,你只要弄懂了复杂声明,typedef 就很好理解!

此外,在 C++11 中推荐使用 using 代替 typedef

 

 


参考链接:GNU Documents

https://whu-pzhang.github.io/define-and-typedef/

https://www.zhihu.com/question/29798061/answer/144423125 作者:平头哥半导体

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值