求助刷固件提示using typedef name-name fpos

配置固件并上传固件 - MakerLab创客实验室
MakerLab创客实验室 — Let's Make something.
已注册用户请
低价、功能全面、配置简单的3d打印机控制方案
配置固件并上传固件
mega 2560板子在3d打印机中相当于大脑,控制这所有的3d打印配件来完成复杂的打印工作,但mega2560不能直接使用,需要上传(upload)固件(firmware)才可以使用。1、下载固件——Marlin由于Marlin固件的强大功能和简单易用,所以这里暂时只介绍Marlin固件。Marlin原版下载地址(很多参数都需要自己配置):我自己配置的Marlin固件大部分参数已经改好:delta机型固件:
我的淘宝店铺:
2、配置固件参数如果你下载的是我提供的固件,那么大部分参数不需要调整,基本上烧入后就可以进行后面的工作了。但下面需要配置的参数还是知道比较好,免得因为固件配置有问题打印机而无法使用。没有提到的参数默认即可。#define BAUDRATE 250000这是配置串口波特率的,只有上位机波特率和固件波特率相同来能通讯成功,一定需要注意。当然也不能随便改,常见的波特率为:,1,5,250000。在3d打印机中常用的是后3个。#define MOTHERBOARD 33 这个参数是配置板子类型的,3d打印机主控板类型非常多,每个板子的io配置不尽相同,所以这个参数必须要跟你自己的板子类型相同,否则无法正常使用。我的板子是RAMPS1.4版本,对应的配置应该为33(单打印头配置),和34(双打印头配置)。如果你使用的是其它板子,请参考旁边的注释并选择合适的配置。#define TEMP_SENSOR_0 1#define TEMP_SENSOR_BED 1这两个参数分别配置温度传感器的类型。这是读取温度是否正常的重要参数,如果读取的温度不正常将不能工作甚至有很大的潜在危险(烧毁器件等)。配置为1说明两个都是100K ntc热敏电阻。如果你使用了其它温度传感器需要根据情况自行更改。#define EXTRUDE_MINTEMP 170 这个参数是为了防止温度未达到而进行挤出操作时带来的潜在风险,如果你做其它3d打印机,比如有朋友做巧克力打印机,挤出温度只需要45度,那么这个参数需要配置为较低数值,比如40度。const bool X_ENDSTOPS_INVERTING =const bool Y_ENDSTOPS_INVERTING =const bool Z_ENDSTOPS_INVERTING = 这里的三个参数是配置3各轴的限位开关类型的,配置为true,限位开关默认状态输出为1,触发状态输出为0,也就是机械限位应该接常开端子。如果你接常闭端子,则将true改为false。#define INVERT_X_DIR false#define INVERT_Y_DIR true这两个参数是比较容易错的。根据自己机械的类型不通,两个的配置不尽相同。但是原则就是要保证原点应该在打印平台的左下角(原点位置为[0,0]),或右上角(原点位置为[max,max])。只有这样打印出来的模型才是正确的,否则会是某个轴的镜像而造成模型方位不对。参考下图坐标。#define X_HOME_DIR -1#define Y_HOME_DIR -1#define Z_HOME_DIR -1 如果原点位置为最小值参数为-1,如果原点位置为最大值配置为1.#define X_MAX_POS 205#define X_MIN_POS 0#define Y_MAX_POS 205#define Y_MIN_POS 0#define Z_MAX_POS 200#define Z_MIN_POS 0 这几个参数是配置打印尺寸的重要参数,参考上面的坐标系图来填写,这里需要说明的是坐标原点并不是打印中心,真正的打印中心一般在[(x.max-x.min)/2,(y.max-y.min)/2]的位置。中心位置的坐标需要在后面的切片工具中使用到,打印中心坐标应该与这里的参数配置匹配,否则很可能会打印到平台以外。#define HOMING_FEEDRATE {50*60, 50*60, 4*60, 0} 配置回原点的速率,单位为毫米每分钟,如果你使用的是xy轴同步带传动,z轴螺杆传动,这个参数可以使用默认值。#define DEFAULT_AXIS_STEPS_PER_UNIT
{85.3,8} 这个参数是打印机打印尺寸是否正确的最重要参数,参数含义为运行1mm各轴所需要的脉冲数,分别对应x,y,z,e四轴。多数情况下这个数字都需要自己计算才可以。计算公式可以参考我的文章。如果你不想自己计算可以用我的计算器:至此,最常用的参数都已经配置完成,可以开始使用了。另外如果你使用了我的MINIPANEL lcd板子还需要改//#define MINIPANEL将前面的//删除掉才可以正常使用。3、上传固件上传之前,windows用户需要提前安装驱动。配置板子类型:Tools & Board & Arduino Mega 2560 ,如图
配置串口: Tools & Serial Port & 你的mega板子对应串口号一般是最后一个,如果是windows系统,串口号一般是com3、com4、com8之类的形式。如图
点击对号按钮来检查是否有错误,如图
再点击向右的箭头按钮来上传固件,如图
上传过程中,2560板子上的TX RX 和L对应的三个led灯都会闪。如果不闪了,说明上传完成,如图
上传完成提示如果上传成功,你就可以进入下一个步骤了,如果上传中出现问题而无法上传,请查看IDE下方的提示框,确认是什么问题后进行进行解决再上传,常见错误板子类型选择错误,串口选择错误等。
本文最后更新于:2 个月前
如果你用于delta机器(并联,三角洲),那么固件请下载这里的: ,大部分参数安装默认即可,只需要配置机器尺寸及比例相关的参数即可
我在编译时delta版本时有错误:Marlin.ino:44:101: fatal error: U8glib.h: No such file or directory
@ 看这里:
为什么电机复位的时候可以动,而要它左转或者右转的时候就只发出声音但不动了?
@?我想研究一下。话说不会编程真是痛苦啊,看着代码他不认识我,我更不认识他
@ 调平代码就在固件里。你可以研究一下
额,能再详细点吗 @
@ 抱歉,涉及代码太多了,说不清楚。并且我也没有研究过太详细。要想研究,就要通读代码
好吧,痛苦 @
讲解的不错!
我按你讲解的方法配置并上传后,Z,E2轴可以动作;X,Y2轴不可以动作.2个温度控制均可工作.不知什么原因?能否指点一下?
@ 打算用E2步进电机口用在Y轴上?什么板子?我的固件?
请问运行之后出现错误:“undefined reference to `setup'” 是怎么回事?
@ 什么代码?
上传后,Z,E 2个轴可以动作;X,Y 2个轴不可以动作. 板子自购的mega2560r3+samps1.4自己下载的marlin,按你的方法配制的. 我的感觉是模拟口作为数字用的x,y轴都有问题.特请教.
@ 我想用3D打印硬件系统做电机驱动,请问怎么通过Arduino软件用G代码写程序?
&&via Android
@ 大神我的固件上传总是提示low memoryavailable,stability problems may occur 然后测试调平都没有问题 但是载入G代码开始打印就不执行 没放映 是那串提示的原因么?
@ low memoryavailable=低可用内存后面是:可能出现稳定问题是不是存东西多了。。。
@ 分析一下3d打印机的固件就知道了。@ 这个错误是在什么情况下出现的?你自己改过固件?改了哪些东西?
&&via Android
@ 板子的烧写不是自动覆盖的嘛?
&&via Android
@ 我也是在网上下的固件 除了教程上的参数其他的没有乱改过 因为读不懂程序都没敢乱动
@ 我说的不是delta的机器结构,是XY方向,有种结构是H型,一根皮带搞定的
@ 可以,打开corexy配置选项
&&via Android
可以发corexy的固件给我吗,我自己diy了一个感觉白弄了。自己根本不会调试。
@ 打开corexy选项,然后接电机就可以了
想问下,打印机运动的时候,为什么走一段时间等几秒,又继续走一会,又停下啊,有遇到这个情况的吗?
@ 我遇到这种情况了,重启
能否留个qq, corexy选项打开就可以了么
#error Oops!
Make sure you have 'Arduino Mega' selected from the 'Tools -& Boards' menu.我下载你的配置 显示这个错误不能上传
我想了解Marlin固件scara的详细坐标转换和说明为什么会超调什么的。
我要做机械臂abb公司那种!
请问一下是要把Marlin文件下所有的文件都上传到arduino里吗? 有的文件arduino显示无法编译 是版本问题吗? 谢谢
&&via Android
请问12864 led的显示器怎么办
请问一下,delta机型里面除了修改机器尺寸参数,还要修改什么地方,能具体点吗?只修改尺寸参数,通上电后,电机一直不转是怎么回事呀?
编译的时候报错,请问是怎么回事exit status 1using typedef-name 'fpos_t' after 'struct'
@ 你现在那个问题解决了么?我现在也碰到遮掩的问题了不知道怎么办了
Powered by
学习系统 基于Rabel记录,总结
typedef用法小结
typedef用法小结
这两天在看程序的时候,发现很多地方都用到typedef,在结构体定义,还有一些数组等地方都大量的用到.但是有些地方还不是很清楚,今天下午,就想好好研究一下.上网搜了一下,有不少资料.归纳一下:来源一:Using typedef to Curb Miscreant CodeTypedef 声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。不管怎样,使用 typedef 能为代码带来意想不到的好处,通过本文你可以学习用 typedef 避免缺欠,从而使代码更健壮。typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法?使用 typedefs 为现有类型创建同义字。定义易于记忆的类型名  typedef 使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于 ''typedef'' 关键字右边。例如:  此声明定义了一个 int 的同义字,名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size:void measure(size * psz);size array[4];size len = file.getlength();std::  typedef 还可以掩饰符合类型,如指针和数组。例如,你不用象下面这样重复定义有 81 个字符元素的数组:char line[81];char text[81];定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:typedef char Line[81];Line text,getline(text);同样,可以象下面这样隐藏指针语法:typedef char *int mystrcmp(pstr, pstr);  这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个‘const char *'类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():int mystrcmp(const pstr, const pstr);  这是错误的,按照顺序,‘const pstr'被解释为‘char * const'(一个指向 char 的常量指针),而不是‘const char *'(指向常量 char 的指针)。这个问题很容易解决:typedef const char *int mystrcmp(cpstr, cpstr); // 现在是正确的记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个 const,以使得该指针本身是常量,而不是对象。代码简化  上面讨论的 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 不是一种特权,而是一种必需。持怀疑态度的人可能会问:"OK,有人还会写这样的代码吗?",快速浏览一下揭示 signal()函数的头文件 ,一个有同样接口的函数。typedef 和存储类关键字(storage class specifier)  这种说法是不是有点令人惊讶,typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。下面将带到第二个陷阱:typedef register int FAST_COUNTER; // 错误  编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。促进跨平台开发  typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以i获得最高的精度: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&。作者简介  Danny Kalev 是一名通过认证的系统分析师,专攻 C++ 和形式语言理论的软件工程师。1997 年到 2000 年期间,他是 C++ 标准委员会成员。最近他以优异成绩完成了他在普通语言学研究方面的硕士论文。业余时间他喜欢听古典音乐,阅读维多利亚时期的文学作品,研究 Hittite、Basque 和 Irish Gaelic 这样的自然语言。其它兴趣包括考古和地理。Danny 时常到一些 C++ 论坛并定期为不同的 C++ 网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。来源二:(;id=4455)C语言中typedef用法1. 基本解释  typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。  在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。  至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐述。 2. typedef & 结构的问题  当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:typedef struct tagNode{ char *pI pNode pN} *pN  答案与分析:  1、typedef的最简单使用typedef long byte_4;  给已知数据类型long起个新名字,叫byte_4。  2、 typedef与结构结合使用typedef struct tagMyStruct{ int iN long lL} MyS  这语句实际上完成两个操作:  1) 定义一个新的结构类型struct tagMyStruct{ int iN long lL};  分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。  我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。  2) typedef为这个新的结构起了一个名字,叫MyStruct。typedef struct tagMyStruct MyS  因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。  答案与分析  C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,上述代码的根本问题在于typedef的应用。  根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。  解决这个问题的方法有多种:  1)、typedef struct tagNode{ char *pI struct tagNode *pN} *pN  2)、typedef struct tagNode *pNstruct tagNode{ char *pI pNode pN};  注意:在这个例子中,你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。  3)、规范做法:struct tagNode{ char *pI struct tagNode *pN};typedef struct tagNode *pN 3. typedef & #define的问题  有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?typedef char *pS#define pStr char *;  答案与分析:  通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:typedef char *pStr1;#define pStr2 char *;pStr1 s1, s2;pStr2 s3, s4;  在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。  #define用法例子:#define f(x) x*xmain( ){ int a=6,b=2,c; c=f(a) / f(b); printf("%d //n",c);}  以下程序的输出结果是: 36。  因为如此原因,在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:#define f(x) (x*x)  当然,如果你使用typedef就没有这样的问题。  4. typedef & #define的另一例  下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?typedef char * pSchar string[4] = "abc";const char *p1 =const pStr p2 =p1++;p2++;  答案与分析:  是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。  #define与typedef引申谈  1) #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。  2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。  5. typedef & 复杂的变量声明  在编程实践中,尤其是看别人代码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:  下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?&1:int *(*a[5])(int, char*);&2:void (*b[10]) (void (*)());&3. doube(*)() (*pa)[9];  答案与分析:  对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。&1:int *(*a[5])(int, char*);//pFun是我们建的一个类型别名typedef int *(*pFun)(int, char*);//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);pFun a[5];&2:void (*b[10]) (void (*)());//首先为上面表达式蓝色部分声明一个新类型typedef void (*pFunParam)();//整体声明一个新类型typedef void (*pFun)(pFunParam);//使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());pFun b[10];&3. doube(*)() (*pa)[9];//首先为上面表达式蓝色部分声明一个新类型typedef double(*pFun)();//整体声明一个新类型typedef pFun (*pFunParam)[9];//使用定义的新类型来声明对象,等价于doube(*)() (*pa)[9];pFunP
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!http://zjf30366.blog.163.com/blog/static//
有种很方便的写法。
typedef int *p;
p pointer;
这时直接把pointer带入原式中,取代p然后去掉typedef,得到的结果就是int * pointer;
哈哈,这样直接替换就很直观多了。
C语言语法简单,但内涵却博大精深;如果在学习时只是止步于表面,那么往往后期会遇到很多困难。typedef是C语言中一个很好用的工具,大量存在于已有代码中,特别值得一提的是:C++标准库实现中更是对typedef有着大量的使用。但很多初学者对其的理解仅局限于:typedef用来定义一个已有类型的"别名(alias)"。正是因为有了这样的理解,才有了后来初学者在typedef int myint和typedef myint int之间的犹豫不决。很多国内大学的C语言课之授课老师也都是如是说的,或者老师讲的不够透彻,导致学生们都是如是理解的。我这里想结合C语言标准文档以及一些代码实例,也说说typedef。
int&&& *p;
这样的代码是C语言中最最基础的一个语句了,大家都知道这个语句声明了一个变量p,其类型是指向整型的指针(pointer to int);如果在这个声明的前面加上一个typedef后,整个语义(semantics)又会是如何改变的呢?
typedef& int&&& *p;
我们先来看看C99标准中关于typedef是如何诠释的?C99标准中这样一小段精辟的描述:"In a declaration whose storage-class specifier is typedef, each declarator defines an identifier to be a typedef name that denotes the type specified for the identifier in the way described in xx"。
参照这段描述,并拿typedef& int&&& *p作为例子来理解:在一个声明中,如果有存储类说明符typedef的修饰,标识符p将被定义为了一个typedef name,这个typedef name表示(denotes)一个类型,什么类型呢?就是int *p这个声明(declarator)中标识符(indentifier)p的类型(int*)。
再比对一下两个声明:
int&&& *p;
typedef& int&&& *p;
是不是有点"茅舍顿开"的感觉,int *p中, p是一个变量,其类型为pointer to int;在int *p前面增加一个typedef后,p变为一个typedef-name,这个typedef-name所表示的类型就是int *p声明式中p的类型(int*)。说句白话,typedef让p去除了普通变量的身份,摇身一变,变成了p的类型的一个typedef-name了。
为了巩固上面的理解,我们再来看看"C语言参考手册(C: A Reference Manual)"中的说法:任何declarator(如typedef int&& *p)中的indentifier(如p)定义为typedef-name, 其(指代p)表示的类型是declarator为正常变量声明(指代int& *p)的那个标识符(指代p)的类型(int*)。有些绕嘴,不过有例子支撑:
typedef double MYDOUBLE; &
去掉typedef ,得到正常变量声明=& double MYDOUBLE;
变量MYDOUBLE的类型为
=& "typedef double MYDOUBLE"中MYDOUBLE是类型double的一个typedef-name。
MYDOUBLE&&& &=& d是一个double类型的变量
typedef double *Dp; &
去掉typedef& ,得到正常变量声明=& double *Dp;
变量Dp的类型为double*,即
=& "typedef double *Dp"中Dp是类型double*的一个typedef-name。
Dp&&& &=& dptr是一个pointer to double的变量
typedef int* Func(int);
去掉typedef& ,得到正常变量声明=& int* Func(int);
变量Func的类型为一个函数标识符,该函数返回值类型为int*,参数类型为
=& "typedef int* Func(int)"中Func是函数类型(函数返回值类型为int*,参数类型为int)的一个typedef-name。
Func&&& * &=& fptr是一个pointer to function with one int parameter, returning a pointer to int
Func&&&&&& 这样的声明意义就不大了。
typedef int (*PFunc)(int);
去掉typedef& ,得到正常变量声明=& int (*PFunc)(int);
变量PFunc的类型为一个函数指针,指向的返回值类型为int,参数类型为int的函数原型;
=& "typedef int (*PFunc)(int)"中PFunc是函数指针类型(该指针类型指向返回值类型为int,参数类型为int的函数)的一个typedef-name。
PFunc&&&& &=& fptr是一个pointer to function with one int parameter, returning int
#include "iostream"
int add(int a,int b){return (a+b);}
typedef int (* func)(int ,int ) ;
void main(){func f =int n = f(1,2);cout && n &&}
typedef&&& int&& A[5];
去掉typedef ,得到正常变量声明 =& int&& A[5];
变量A的类型为一个含有5个元素的整型数组;
=& "typedef&&& int&& A[5]"中A是含有5个元素的数组类型的一个typedef-name。
A&& a = {3, 4, 5, 7, 8};
A&& b = { 3, 4, 5, 7, 8, 9}; /* 会给出Warning: excess elements in array initializer */
typedef&&& int&& (*A)[5]; (注意与typedef&&& int*&&& A[5]; 区分)
去掉typedef ,得到正常变量声明 =& int&& (*A)[5];
变量A的类型为pointer to an array with 5 int elements;
=& "typedef&&& int&& (*A)[5]"中A是"pointer to an array with 5 int elements"的一个typedef-name。
int&& c[5] = {3, 4, 5, 7, 8}; &
A&&& a = &c;
printf("%d\n", (*a)[0]); /* output: 3 */
如果这样赋值:
int&& c[6] = {3, 4, 5, 7, 8, 9}; &
A&&& a = &c; /* 会有Warning: initialization from incompatible pointer type */
typedef struct _Foo_t Foo_t;
去掉typedef ,得到正常变量声明 =& struct _Foo_t Foo_t;
变量Foo_t的类型为struct _Foo_t;
=& "typedef struct _Foo_t Foo_t"中Foo_t是"struct _Foo_t"的一个typedef-name。
typedef&& struct { ... // }&& Foo_t;
去掉typedef ,得到正常变量声明 =& struct { ... // }&& Foo_t;
变量Foo_t的类型为struct { ... // } ;
=& "typedef&& struct { ... // }&& Foo_t
"中Foo_t是"struct { ... // }"的一个typedef-name。这里struct {...//}是一个无"标志名称(tag
name)"的结构体声明。
参考资料:
1、"ISOIEC-(E)--Programming Languages--C"之Page 123;
2、C语言参考手册(中文版) 之 Page 119
http://www.cnblogs.com/lkkandsyf/archive//4461389.html
类型定义的语法可以归结为一句话:只要在变量定义前面加上typedef,就成了类型定义。这儿的原本应该是变量的东西,就成为了类型。
&&&& //整型变量int *&& //整型指针变量int array [5]; //整型数组变量int *p_array [5]; //整型指针的数组的变量int (*array_pointer) [5];//整型数组的指针的变量int function (int param);//函数定义,也可将函数名看作函数的变量int *function (int param);//仍然是函数,但返回值是整型指针int (*function) (int param);//现在就是指向函数的指针了
若要定义相应类型,即为类型来起名字,就是下面的形式:typedef int integer_t;&&&&&&&&&&&&&&&&&&&&& //整型类型typedef int *pointer_t;&&&& //整型指针类型typedef int array_t [5]; //整型数组类型typedef int *p_array_t [5];&&& //整型指针的数组的类型typedef int (*array_pointer_t) [5]; //整型数组的指针的类型typedef int function_t (int param);&&&& //函数类型typedef int *function_t (int param);&&& //函数类型typedef int (*function_t) (int param); //指向函数的指针的类型注意:上面的函数类型在C中可能会出错,因为C中并没有函数类型,它的函数变量会自动退化成函数指针;在C++中好像是可以的。在这里主要说明的是形式上的相似性.
typedef的一般形式为:typedef&& 类型&&&& 定义名;在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。其实,在C语言中声明变量的时候,有个存储类型指示符(storage-class-specifier),它包括我们熟悉的extern、static、auto、register。在不指定存储类型指示符的时候,编译器会根据约定自动取缺省值。另外,存储类型指示符的位置也是任意的(但要求在变量名和指针*之前),也就是说以下几行代码是等价的:根据C语言规范,在进行句法分析的时候,typedef和存储类型指示符是等价的!所以,我们把上述使用static的地方替换为typedef:上述代码的语义是:将i定义为一个类型名,其等价的类型为const int。以后如果我们有i&& a代码,就等价于const int a。对于有指针的地方也是一样的,比如:int const typedef *t;那么代码t&& p。就相当于int const *p。另外,typedef不能和static等存储类型指示符同时使用,因为每个变量只能有一种存储类型,所以代码:是非法的。
typedef有两种用法:一、一般形式,定义已有类型的别名  typedef&& 类型&&& 定义名;二、创建一个新的类型&&&& typedef&& 返回值类型&& 新类型名(参数列表);
1)typedef int NUM[10];//声明整型数组类型
&&& NUM//定义n为整型数组变量,其中n[0]--n[9]可用
2)typedef char* STRING;//声明STRING为字符指针类型
&&& STRING p,s[10];//p为字符指针变量,s为指针数组
3)typedef int (*POINTER)();//声明POINTER为指向函数的指针类型,该函数返回整型值,没有参数
&&& POINTER P1,P2;//p1,p2为POINTER类型的指针变量
&&&&& 1)用typedef可以声明各种类型名,但不能用来定义变量,用typedef可以声明数组类型、字符串类型、使用比较方便。
例如:定义数组,原来是用:int a[10],b[10],c[10],d[10];由于都是一维数组,大小也相同,可以先将此数组类型声明为一个名字:
typedef int ARR[10];
然后用ARR去定义数组变量:
ARR a,b,c,d;//ARR为数组类型,它包含10个元素。因此a,b,c,d都被定义为一维数组,含10个元素。可以看到,用typedef可以将 数组类型 和 数组变量 分离开来,利用数组类型可以定义多个数组变量。同样可以定义字符串类型、指针类型等。
&&&&& 2)用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
&&&&& 3)typedef与#define有相似之处,但事实上二者是不同的,#define是在 预编译 时处理,它只能做简单的字符串替换,而typedef是在 编译时 处理的。它并不是做简单的字符串替换,而是采用如同 定义变量 的方法那样来 声明 一个类型。
例如:typedef int COUNT;和#define COUNT int的作用都是用COUNT代表int,单事实上它们二者是不同的。
两个陷阱:
陷阱一:&记住,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; //不可行编译将失败,会提示“指定了一个以上的存储类”。
1.typedef &函数指针的使用方法
(1)typedef 首先是用来定义新的类型,i.e typedef struct {.....}
在以后引用时,就可以用 mystruct 来定义自己的结构体,mystruct structname1,mystruct
structname2.
(2)typedef 常用的地方,就在定义函数指针,行为和宏定义类似,用实际类型替换同义字,但是有区别:&typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。
案例一:&通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:&typedef char *pStr1;&#define pStr2 char *;&pStr1 s1, s2;&pStr2 s3, s4;&在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。&案例二:&下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?&typedef char * pS&char string[4] = "abc";&const char *p1 =&const pStr p2 =&p1++;&p2++;&是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const
pStr p2并不等于const char * p2。const pStr p2和const long
x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr
p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
&typedef &返回类型(*新类型)(参数表)
&typedef int ( * MYFUNCTION )(&int,int&); 这种用法一般是在定义函数指针 MYFUNCTION 是一个函数指针类型 有两个整型的参数,返回一个整型。
在对于这样的形式,去掉typedef和别名 就剩下了的是原变量的类型 如:int (*)(int ,int); 在函数指针中,抽象得看待函数,函数名其实就是一个地址,函数名指向该函数的代码在内存的首地址。
用法二: 复杂函数声明类型
&下面是三个变量的声明 &用typedef 如何来做???
&1 int *(*a[5])(void *,void *);
&2 void (*b[5])(void (*)());
&3 float (*)()(*pa)[10];
分析如下:
&1 int *(*a[5])(void *,void *);
//pFUN是自己建立的类型别名 typedef int *(* pFUN)(void &*,void *); //等价于int *(*a[5])(void *,void *);&
pFUN a[5]; &a是一个数组,包含五个元素,这些元素都是函数指针,该函数指针所指的函数的返回值是int的指针 输入参数有两个都是void *.
&2&void (*b[5])( void (*)() );
// first 为蓝色的 声明一个新的类型 typedef void (*pFUNParam)( );
//整体声明一个新类型 &typedef void (*pFUN)(FUNParam);&
//使用定义的新类型声明对象 等价于void (*b[5])( void (*)() );&
pFUN b[5]; b 是一个含有5个元素的数组,每个元素都是一个函数指针,该函数指针所指的函数的返回值是void.输入参数是另一个函数指针,这个函数指针没有参数,返回值为空。在这里套用了连续的函数指针。本身就是一个函数指针,而且参数也是一个函数指针。
&3&float (*)()(*pa)[10];
//first 为上面的蓝色表达式声明一个新类型 typedef float (*pFUN)();&
//整体声明一个新类型typedef pFUN (* pFunParam)[10];
//使用定义的新类型来声明对象 等价与float (*)()(*pa)[10];
pa 是一个指针,指针指向一个含有10个元素的数组,数组的元素是函数指针,函数指针所指的函数没有输入参数,返回值为float.
**********************************************
使用typedef简化复杂的变量声明1)、定义一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数,并返回一个整型?第一种方法:int (*a[10])(int);第二种方法:typedef int (*pfunc)(int);&&&&&&&&&&&& pfunc a[10];2)、定义一个有10个指针的数组,该指针指向一个函数,该函数有一个函数指针(不带参数,返回值为空)参数,并返回空。第一种方法:void (*a[10])(void (*)(void));第二种方法:typedef void (*pfuncParam)(void);&&&&&&&&&&&&&& typedef void (*pfunc)(pfuncParam);pfunc a[10];3)、一个指向有10个函数指针(不带参数,返回值为double)数组的指针第一种方法:double (*)(void) (*p)[10];第二种方法:typedef double (*pfunc)(void);&&&&&&&&&&&& typedef pfunc (*pfuncParam)[10];&&&&&&&&&&&& pfuncP
从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例: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'' 关键字右边。例如:此声明定义了一个 int 的同义字,名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size:void
measure(size * psz); size array[4];size len =
file.getlength();std::vector &size& typedef
还可以掩饰符合类型,如指针和数组。例如,你不用象下面这样重复定义有 81 个字符元素的数组:char line[81];char text[81];定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:typedef char Line[81]; Line text,getline(text);同样,可以象下面这样隐藏指针语法:typedef
char *int mystrcmp(pstr, pstr);这里将带我们到达第一个 typedef 陷阱。标准函数
strcmp()有两个‘const char *'类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():int
mystrcmp(const pstr, const pstr); 这是错误的,按照顺序,‘const pstr'被解释为‘char *
const'(一个指向 char 的常量指针),而不是‘const char *'(指向常量 char 的指针)。这个问题很容易解决:typedef
const char * int mystrcmp(cpstr, cpstr); //
现在是正确的记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个
const,以使得该指针本身是常量,而不是对象。&代码简化上面讨论的 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
不是一种特权,而是一种必需。持怀疑态度的人可能会问:“OK,有人还会写这样的代码吗?”,快速浏览一下揭示 signal()函数的头文件
&csinal&,一个有同样接口的函数。&typedef 和存储类关键字(storage class specifier)这种说法是不是有点令人惊讶,typedef
就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并是说 typedef
会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern
等类型的变量声明。下面将带到第二个陷阱:typedef register int FAST_COUNTER; //
错误编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef
声明中不能用 register(或任何其它存储类关键字)。&促进跨平台开发typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以i获得最高的精度: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&char,
char_traits&char&,allocator&char&& 和
basic_ofstream&char, char_traits&char&&。
阅读(...) 评论()}

我要回帖

更多关于 using name space std 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信