为您找到与c语言中typedef相关的共166个结果:
c语言中typedef的用法的用法你知道吗?下面小编就跟你们详细介绍下c语言中typedef的用法的用法,希望对你们有用。
一.基本概念剖析
int* (*a[5])(int, char*); https://#1
void (*b[10]) (void (*)()); https://#2
double(*)() (*pa)[9]; https://#3
1.C语言中函数声明和数组声明。函数声明一般是这样:
int fun(int, double);
对应函数指针(pointer to function)的声明是这样:
int (*pf)(int, double);
可以这样使用:
pf = &fun; https://赋值(assignment)操作
(*pf)(5, 8.9);https://函数调用操作
也请注意,C语言本身提供了一种简写方式如下:
pf = fun; https:// 赋值(assignment)操作
pf(5, 8.9); https:// 函数调用操作
不过我本人不是很喜欢这种简写,它对初学者带来了比较多的迷惑。
数组声明一般是这样:
int a[5];
对于数组指针(pointer to array)的声明是这样:
int (*pa)[5];
可以这样使用:
pa = &a; https:// 赋值(assignment)操作
int i = (*pa)[2]; https:// 将a[2]赋值给i;
2.有了上面的基础,我们就可以对付开头的三只纸老虎了!:) 这个时候你需要复习一下各种运算符的优先顺序和结合顺序了,顺便找本书看看就够了。
#1:int* (*a[5])(int, char*);
首先看到标识符名a,“[]”优先级大于“*”,a与“[5]”先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,
指针指向“(int, char*)”,对,指向一个函数,函数参数是“int, char*”,返回值是“int*”。完毕,我们干掉了第一个纸老虎。:)
#2:void (*b[10]) (void (*)());
b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是“void (*)()”【注1】,返回值是“void”。完毕!
注1:这个参数又是一个指针,指向一个函数,函数参数为空,返回值是“void”。
#3:double(*)()(*pa)[9];
pa是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是“double(*)()”【也即一个指针,指向一个函数,函数参数为空,返回值是“double
---------------------------------------------------------------
#1:int* (*a[5])(int, char*);
typedef int* (*PF)(int, char*);https://PF是一个类型别名【注2】。
PF a[5];https://跟int* (*a[5])(int, char*);的效果一样!
注2:很多初学者只知道typedef char* pchar;但是对于typedef的其它用法不太了解。Stephen Blaha对typedef用法做过一个总结:“建立一个类型别名的方法很简单,在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头”。
#2:void (*b[10])(void (*)());
typedef void (*pfv)();
typedef void (*pf_taking_pfv)(pfv);
pf_taking_pfv b[10]; https://跟void (*b[10]) (void (*)());的效果一样!
#3. double(*)()(*pa)[9];
typedef double(*PF)();
typedef PF (*PA)[9];
PA pa; https://跟doube(*)()(*pa)[9];的效果一样!
3.const和volatile在类型声明中的位置。
在这里我只说const,volatile是一样的!【注3】
注3:顾名思义,volatile修饰的量就是很容易变化,不稳定的量,它可能被其它线程,操作系统,硬件等等在未知的时间改变,
所以它被存储在内存中,每次取用它的时候都只能在内存中去读取,它不能被编译器优化放在内部寄存器中。
类型声明中const用来修饰一个常量,我们一般这样使用:const在前面:
const int; https://int是const
const char*;https://char是const
char* const;https://*(指针)是const
const char* const;https://char和*都是const
对初学者,const char*和 char* const是容易混淆的。这需要时间的历练让你习惯它。 上面的声明有一个对等的写法:const在后面:
int const; https://int是const
char const*;https://char是const
char* const;https://*(指针)是const
char const* const;https://char和*都是const
第一次你可能不会习惯,但新事物如果是好的,我们为什么要拒绝它呢?:)const在后面有两个好处:
A.const所修饰的类型正好是在它前面的那一个。如果这个好处还不能让你动心的话,那请看下一个!
B.我们很多时候会用到typedef的类型别名定义。比如typedef char* pchar,如果用const来修饰的话,
当const在前面的时候,就是const pchar,你会以为它就是const char* ,但是你错了,它的真实含义是char* const。
是不是让你大吃一惊!但如果你采用const在后面的写法,意义就怎么也不会变,不信你试试!
不过,在真实项目中的命名一致性更重要。你应该在两种情况下都能适应,并能自如的转换,公司习惯,
商业利润不论在什么时候都应该优先考虑!不过在开始一个新项目的时候,你可以考虑优先使用const在后面的习惯用法。
二.Typedef声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。
不管怎样,使用 typedef 能为代码带来意想不到的好处,通过本文你可以学习用typedef避免缺欠,从而使代码更健壮。
typedef声明,简称typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。
所谓美观,意指typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。
本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱,如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法.
typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于typedef关键字右边。
例如:typedef int size;
此声明定义了一个 int 的同义字,名字为 size。注意typedef并不创建新的类型。它仅仅为现有类型添加一个同义字。
你可以在任何需要 int 的上下文中使用 size:
void measure(size * psz);
size array[4];
size len = file.getlength();
typedef 还可以掩饰复合类型,如指针和数组。例如,你不用象下面这样重复定义有81个字符元素的数组:
char line[81]; char text[81];
定义一个typedef,每当要用到相同类型和大小的数组时,可以这样:
typedef char Line[81];
Line text, secondline;
getline(text);
同样,可以象下面这样隐藏指针语法:
typedef char * pstr;
int mystrcmp(pstr, pstr);
这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个const char *类型的参数。因此,它可能会误导人们象下面这样声明:
int mystrcmp(const pstr, const pstr);
这是错误的,事实上,const pstr被编译器解释为char * const(一个指向 char 的常量指针),而不是const char *(指向常量 char 的指针)。
这个问题很容易解决:
typedef const char * cpstr;
int mystrcmp(cpstr, cpstr);
上面讨论的 typedef 行为有点像 #define 宏,用其实际类型替代同义字。不同点是typedef在编译时被解释
,因此让编译器来应付超越预处理器能力的文本替换。例如:
typedef int (*PF) (const char *, const char *);
这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:
PF Register(PF pf);
Register()的参数是一个PF类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:
int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *);
很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,
而是一种必需。typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。
这并不是说typedef会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。
下面将带到第二个陷阱:
typedef register int FAST_COUNTER; https:// 错误编译通不过
问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,
在 typedef 声明中不能用 register(或任何其它存储类关键字)。typedef 有另外一个重要的用途,那就是定义机器无关的类型,
例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以获得最高的精度:
typedef long double REAL;
在不支持 long double 的机器上,该 typedef 看起来会是下面这样:
typedef double REAL;
并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:
typedef float REAL;
你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 REAL 类型的应用程序。唯一要改的是 typedef 本身。
在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。不是吗?
标准库广泛地使用 typedef 来创建这样的平台无关类型:size_t,ptrdiff 和 fpos_t 就是其中的例子。
此外,象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的,难以理解的模板特化语法,
例如:basic_string,allocator> 和 basic_ofstream>。
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; https:// 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
https:// 和一个字符变量;
以下则可行:
typedef char* PCHAR; https:// 一般用大写
PCHAR pa, pb; https:// 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,则可以直接写:结构名 对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; https:// 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与平台无关的类型。
比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef long double REAL;
在不支持 long double 的平台二上,改为:
typedef double REAL;
在连 double 都不支持的平台三上,改为:
typedef float REAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:
1. 原声明:int *(*a[5])(int, char*);
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int *(*pFun)(int, char*);
原声明的最简化版:
pFun a[5];
2. 原声明:void (*b[10]) (void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
3. 原声明:doube(*)() (*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
int (*func)(int *p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int *);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。
也可以记住2个模式:
type (*)(....)函数指针
type (*)[]数组指针
---------------------------------
陷阱一:
记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
先定义:
typedef char* PSTR;
然后:
int mystrcmp(const PSTR, const PSTR);
const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。
陷阱二:
typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; https://不可行
编译将失败,会提示“指定了一个以上的存储类”。
”】。(注意typedef int* p[9]与typedef int(*p)[9]的区别,前者定义一个数组,此数组包含9个int*类型成员,而后者定义一个指向数组的指针,被指向的数组包含9个int类型成员)。
现在是不是觉得要认识它们是易如反掌,工欲善其事,必先利其器!我们对这种表达方式熟悉之后,就可以用“typedef”来简化这种类型声明。
浏览量:2
下载量:0
时间:
typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。下面小编就跟大家分享下C语言中typedef用法。
一.基本概念剖析
int* (*a[5])(int, char*); https://#1
void (*b[10]) (void (*)()); https://#2
double(*)() (*pa)[9]; https://#3
1.C语言中函数声明和数组声明。函数声明一般是这样:
int fun(int, double);
对应函数指针(pointer to function)的声明是这样:
int (*pf)(int, double);
可以这样使用:
pf = &fun; https://赋值(assignment)操作
(*pf)(5, 8.9);https://函数调用操作
也请注意,C语言本身提供了一种简写方式如下:
pf = fun; https:// 赋值(assignment)操作
pf(5, 8.9); https:// 函数调用操作
不过我本人不是很喜欢这种简写,它对初学者带来了比较多的迷惑。
数组声明一般是这样:
int a[5];
对于数组指针(pointer to array)的声明是这样:
int (*pa)[5];
可以这样使用:
pa = &a; https:// 赋值(assignment)操作
int i = (*pa)[2]; https:// 将a[2]赋值给i;
2.有了上面的基础,我们就可以对付开头的三只纸老虎了!:) 这个时候你需要复习一下各种运算符的优先顺序和结合顺序了,顺便找本书看看就够了。
#1:int* (*a[5])(int, char*);
首先看到标识符名a,“[]”优先级大于“*”,a与“[5]”先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,
指针指向“(int, char*)”,对,指向一个函数,函数参数是“int, char*”,返回值是“int*”。完毕,我们干掉了第一个纸老虎。:)
#2:void (*b[10]) (void (*)());
b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是“void (*)()”【注1】,返回值是“void”。完毕!
注1:这个参数又是一个指针,指向一个函数,函数参数为空,返回值是“void”。
#3:double(*)()(*pa)[9];
pa是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是“double(*)()”【也即一个指针,指向一个函数,函数参数为空,返回值是“double
---------------------------------------------------------------
#1:int* (*a[5])(int, char*);
typedef int* (*PF)(int, char*);https://PF是一个类型别名【注2】。
PF a[5];https://跟int* (*a[5])(int, char*);的效果一样!
注2:很多初学者只知道typedef char* pchar;但是对于typedef的其它用法不太了解。Stephen Blaha对typedef用法做过一个总结:“建立一个类型别名的方法很简单,在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头”。
#2:void (*b[10])(void (*)());
typedef void (*pfv)();
typedef void (*pf_taking_pfv)(pfv);
pf_taking_pfv b[10]; https://跟void (*b[10]) (void (*)());的效果一样!
#3. double(*)()(*pa)[9];
typedef double(*PF)();
typedef PF (*PA)[9];
PA pa; https://跟doube(*)()(*pa)[9];的效果一样!
3.const和volatile在类型声明中的位置。
在这里我只说const,volatile是一样的!【注3】
注3:顾名思义,volatile修饰的量就是很容易变化,不稳定的量,它可能被其它线程,操作系统,硬件等等在未知的时间改变,
所以它被存储在内存中,每次取用它的时候都只能在内存中去读取,它不能被编译器优化放在内部寄存器中。
类型声明中const用来修饰一个常量,我们一般这样使用:const在前面:
const int; https://int是const
const char*;https://char是const
char* const;https://*(指针)是const
const char* const;https://char和*都是const
对初学者,const char*和 char* const是容易混淆的。这需要时间的历练让你习惯它。 上面的声明有一个对等的写法:const在后面:
int const; https://int是const
char const*;https://char是const
char* const;https://*(指针)是const
char const* const;https://char和*都是const
第一次你可能不会习惯,但新事物如果是好的,我们为什么要拒绝它呢?:)const在后面有两个好处:
A.const所修饰的类型正好是在它前面的那一个。如果这个好处还不能让你动心的话,那请看下一个!
B.我们很多时候会用到typedef的类型别名定义。比如typedef char* pchar,如果用const来修饰的话,
当const在前面的时候,就是const pchar,你会以为它就是const char* ,但是你错了,它的真实含义是char* const。
是不是让你大吃一惊!但如果你采用const在后面的写法,意义就怎么也不会变,不信你试试!
不过,在真实项目中的命名一致性更重要。你应该在两种情况下都能适应,并能自如的转换,公司习惯,
商业利润不论在什么时候都应该优先考虑!不过在开始一个新项目的时候,你可以考虑优先使用const在后面的习惯用法。
二.Typedef声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。
不管怎样,使用 typedef 能为代码带来意想不到的好处,通过本文你可以学习用typedef避免缺欠,从而使代码更健壮。
typedef声明,简称typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。
所谓美观,意指typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。
本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱,如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法.
typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于typedef关键字右边。
例如:typedef int size;
此声明定义了一个 int 的同义字,名字为 size。注意typedef并不创建新的类型。它仅仅为现有类型添加一个同义字。
你可以在任何需要 int 的上下文中使用 size:
void measure(size * psz);
size array[4];
size len = file.getlength();
typedef 还可以掩饰复合类型,如指针和数组。例如,你不用象下面这样重复定义有81个字符元素的数组:
char line[81]; char text[81];
定义一个typedef,每当要用到相同类型和大小的数组时,可以这样:
typedef char Line[81];
Line text, secondline;
getline(text);
同样,可以象下面这样隐藏指针语法:
typedef char * pstr;
int mystrcmp(pstr, pstr);
这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个const char *类型的参数。因此,它可能会误导人们象下面这样声明:
int mystrcmp(const pstr, const pstr);
这是错误的,事实上,const pstr被编译器解释为char * const(一个指向 char 的常量指针),而不是const char *(指向常量 char 的指针)。
这个问题很容易解决:
typedef const char * cpstr;
int mystrcmp(cpstr, cpstr);
上面讨论的 typedef 行为有点像 #define 宏,用其实际类型替代同义字。不同点是typedef在编译时被解释
,因此让编译器来应付超越预处理器能力的文本替换。例如:
typedef int (*PF) (const char *, const char *);
这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:
PF Register(PF pf);
Register()的参数是一个PF类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:
int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *);
很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,
而是一种必需。typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。
这并不是说typedef会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。
下面将带到第二个陷阱:
typedef register int FAST_COUNTER; https:// 错误编译通不过
问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,
在 typedef 声明中不能用 register(或任何其它存储类关键字)。typedef 有另外一个重要的用途,那就是定义机器无关的类型,
例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以获得最高的精度:
typedef long double REAL;
在不支持 long double 的机器上,该 typedef 看起来会是下面这样:
typedef double REAL;
并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:
typedef float REAL;
你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 REAL 类型的应用程序。唯一要改的是 typedef 本身。
在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。不是吗?
标准库广泛地使用 typedef 来创建这样的平台无关类型:size_t,ptrdiff 和 fpos_t 就是其中的例子。
此外,象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的,难以理解的模板特化语法,
例如:basic_string,allocator> 和 basic_ofstream>。
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; https:// 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
https:// 和一个字符变量;
以下则可行:
typedef char* PCHAR; https:// 一般用大写
PCHAR pa, pb; https:// 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,则可以直接写:结构名 对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; https:// 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与平台无关的类型。
比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef long double REAL;
在不支持 long double 的平台二上,改为:
typedef double REAL;
在连 double 都不支持的平台三上,改为:
typedef float REAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:
1. 原声明:int *(*a[5])(int, char*);
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int *(*pFun)(int, char*);
原声明的最简化版:
pFun a[5];
2. 原声明:void (*b[10]) (void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
3. 原声明:doube(*)() (*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
int (*func)(int *p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int *);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。
也可以记住2个模式:
type (*)(....)函数指针
type (*)[]数组指针
---------------------------------
陷阱一:
记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
先定义:
typedef char* PSTR;
然后:
int mystrcmp(const PSTR, const PSTR);
const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。
陷阱二:
typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; https://不可行
编译将失败,会提示“指定了一个以上的存储类”。
”】。(注意typedef int* p[9]与typedef int(*p)[9]的区别,前者定义一个数组,此数组包含9个int*类型成员,而后者定义一个指向数组的指针,被指向的数组包含9个int类型成员)。
现在是不是觉得要认识它们是易如反掌,工欲善其事,必先利其器!我们对这种表达方式熟悉之后,就可以用“typedef”来简化这种类型声明。
浏览量:2
下载量:0
时间:
语言是人类最重要的交际工具,是人们进行沟通交流的主要表达方式。那么你知道语言的英文是什么吗?下面读文网小编为大家带来语言的英文表达和相关例句,供大家参考学习。
spoken and written language;
语言与文字
working language;
工作语言
official language
正式语言
assembly language
汇编语言
浏览量:6
下载量:0
时间:
网络语言是指产生并运用于网络的语言,具有高效、便捷、准确的特征。网络语言是从网络中产生或应用于网络交流的一种语言 ,越来越成为人们网络生活中必不可少的一部分。那么你知道网络语言用英语怎么说吗?下面跟着读文网小编一起来学习一下吧。
1. English will possibly decline in use as the major Internet language.
英语作为主要的网络语言,其使用有可能会下降.
2. Laurie Anderson is giving new meaning to the developing language of cyberspace.
罗莉安德森给了网络语言的发展下了新定义.
3. The use of partial tone in network language makes It'show charming.
而许多网络词语和语句正是运用了谐音的手段,使网络语言呈现出其特有的魅力.
4. The network language fancy numberless as the sand, enumerate.
网络语言中的奇思异想可谓多如牛毛, 不胜枚举.
5. The popularization of computers and network brought about the net language.
计算机与网络的普及,催生了网络语言.
6. At last the paper discusses the development and standardization of network language.
最后,文章对网络语言的发展和规范化问题进行了探讨.
7. Many characteristics of internet language implicate post - modern values and cultural connotations.
摘要网络语言的许多特点暗合了后现代的价值观念和文化内涵.
8. Language chat and convenient to use the network!
使用网络语言聊天又方便!
9. Cyber language not only enriches our school life but also eases the pressures of studying.
网络语言不仅丰富了我们的校园生活同时也减轻课业压力.
10. On the definition of language network really different people - see, people from different focus definition.
作为一种新的语言现象, 网络语言越来越引起人们的关注.
11. The net language has been drawing more and more attention for its peculiarities.
网络语言作为语言中的一个新生事物,已受到越来越多的人的关注.
12. Using a computer keyboard is the special character of network language dedicating a characteristic.
利用计算机键盘上的特殊字符表情达意也是网络语言的一个特点.
13. XML, which will act as the next generation WEB language, has gained more success.
XML作为下一代的网络语言, 其应用更是大行其道.
14. Bengchu a few and the language network, and that does not match the times.
并且不时的蹦出几句网络语言, 和与那个时代不相符的东西.
15. With the prevalence of cyber language are increasingly heated arguments over its nature and semantic feature.
随着网络语言的流行,关于其性质和语义特征的争论愈发激烈.
浏览量:3
下载量:0
时间:
肢体语言是指通过头、眼、颈、手、肘、臂、身、胯、足等人体部位的协调活动来传达人物的思想,形象地借以表情达意的一种沟通方式。那么你知道肢体用英语怎么说吗?下面来学习一下吧。
1. Her expression is concerned but her body-language does not correspond.
她满脸关切之情,但她的肢体语言并非如此。
2. His gestures were economical, his words generally mild.
他的肢体语言极尽简化,措词总体温和。
3. Body language can also be used to attract members of the opposite sex.
肢体语言也可以用来吸引异性的注意。
4. Read their body language. Are their eyes wandering or are they drumming the desk with their fingers?
解读他们的肢体语言。他们的眼睛游离不定吗,抑或他们在用手指不停地敲打桌子?
5. Open body language makes you appear more approachable and trustworthy.
开放式肢体语言让你看起来更加得平易近人和可信赖.
6. There is no advice on how to use your body language.
如何使用肢体语言没有定式.
7. Finally, the transcript does not carry inflections of voice and body language.
最后, 记录手本其实不反映声音和肢体语言.
8. How would you do if you are desertd to an isolated island?
从他的面部表情和肢体语言你会看出他是否想要聊天.
9. Using the right body language helps you communicate more assertively.
使用正确的肢体语言会帮助你更有主张力的交流.
10. Use the right body language to get your message across.
用正确的肢体语言帮助传达信息.
11. Mr Obama's body language was easy without being ingratiating.
奥巴马的肢体语言既随和,又无逢迎之意.
12. Body language is the quiet, secret and most powerful language of all!
肢体语言是安静的, 秘密的,并且也是所有的语言中最强有力的!
13. People want to see your face, expressions and read your body language.
人们想要看到你的面孔, 看到并阅读你的肢体语言.
14. The Chinese people don't use body language as often as foreigners do.
中国人并不像外国人那样经常使用肢体语言.
15. This nonverbal way of communication is called body language.
这种不用语言沟通的方法叫做肢体语言.
浏览量:2
下载量:0
时间:
C语言是一门实践性和动手能力要求很高的大学主干课程,但是C语言实验课的教学一直不受重视,教学效果也不太理想。下面小编就跟你们详细介绍下c语言中else的用法,希望对你们有用。
if(表达式)
语句1;
else
语句2;
其语义是:如果表达式的值为真,则执行语句1,否则执行语句2 。其执行过程可表示如下。
#include <stdio.h>
int main(void){
int a, b;
printf("input two numbers: ");
scanf("%d%d",&a,&b);
if(a>b)
printf("max=%d",a);
else
printf("max=%d",b);
return 0;
}
输入两个整数,输出其中的大数。改用if-else语句判别a,b的大小,若a大,则输出a,否则输出b。
浏览量:12
下载量:0
时间:
C语言作为一门新型高级编程语言,在计算机软件编程中具有较为广泛的应用和实现。下面小编就跟你们详细介绍下c语言中const的用法,希望对你们有用。
const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。
虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题。
问题:const变量 & 常量
为什么我象下面的例子一样用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢?
const int n = 5;
int a[n];
答案与分析:
1)、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的,例如5, “abc”,等,肯定是只读的,因为程序中根本没有地方存放它的值,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符(Qualifier)。上述代码中变量n被修饰为只读变量,可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”,“只读变量”也是不可以的。
2)、注意:在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而const int n,n只是一个变量(常量 != 不可变的变量,但在标准C++中,这样定义的是一个常量,这种写法是对的),实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C对数组的规定限制了它。
3)、那么,在ANSI C 语言中用什么来定义常量呢?答案是enum类型和#define宏,这两个都可以用来定义常量。
问题:const变量 & const 限定的内容
下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
答案与分析:
问题出在p2++上。
1)、const使用的基本形式: const char m; 限定m不可变。
2)、替换1式中的m, const char *pm; 限定*pm不可变,当然pm是可变的,因此问题中p1++是对的。
3)、替换1式char, const newType m; 限定m不可变,问题中的charptr就是一种新类型,因此问题中p2不可变,p2++是错误的。
问题:const变量 & 字符串常量
请问下面的代码有什么问题?
char *p = "i'm hungry!";
p[0]= 'I';
答案与分析:
上面的代码可能会造成内存的非法写操作。分析如下, “i'm hungry”实质上是字符串常量,而常量往往被编译器放在只读的内存区,不可写。p初始指向这个只读的内存区,而p[0] = 'I'则企图去写这个地方,编译器当然不会答应。
问题:const变量 & 字符串常量2
请问char a[3] = "abc" 合法吗?使用它有什么隐患?
答案与分析:
在标准C中这是合法的,但是它的生存环境非常狭小;它定义一个大小为3的数组,初始化为“abc”。注意,它没有通常的字符串终止符'