当前位置:文档之家› C++预处理器,typeid与强制类型转换专题

C++预处理器,typeid与强制类型转换专题

C++预处理器,typeid与强制类型转换专题
C++预处理器,typeid与强制类型转换专题

本文作者:黄邦勇帅(编著)(原名:黄勇)

本文是属于学习C++的附加内容,本文主要讲解了预处理器,#define,#if指令,typid的作用与使用方法,C++使用的四种强制类型转换,其中对dynamic_cast和reinterpret_cast两种转换作了深入细致的讲解。本文由浅入深易学易懂,内容全面,是学习C++的不错的资料,相信本文能给读者带来对C++的重新认识和更深入的理解。

本文使用的是x86机器(主流计算机都是x86机器),windows xp操作系统,VC++2010编译器进行讲解的。

本文内容完全属于个人见解与参考文现的作者无关,限于水平有限,其中难免有误解之处,望指出更正。

声明:禁止抄袭,复印,转载本文,本文作者拥有完全版权。

主要参考文献:

1、C++.Primer.Plus.第五版.中文版[美]Stephen Prata著孙建春韦强译人民邮电出版社 2005年5月

2、C++.Primer第四版.中文版 Stanley B.Lippman、Barbara E.Moo、Josee Lajoie著李师贤、蒋爱军等译人民邮电出版社 2006年3月

3、C++.Primer第三版.中文版 Stanley B.Lippman、Josee Lajoie著潘爱民、张丽等译中国电力版社 2002年5月

4、《C++程序设计》作者谭浩强清华大学出版社 2004年6月

5、《C++程序设计语言》特别版[美]Bjarne Stroustrup著裘宗燕译机械工业出版社 2010年3月

第18部分 C++预处理器,typeid与强制类型转换专题(2016-7-14)

(共5页)

1、预处理器:预处理器是编译器把C++代码编译为机器指令之前执行的一个过程,所有的预处理器都以#开头,以便

与C++语句区分开来,#include预处理器指令在前面已经用过不少了

2、注意:预处理器指令必须作为第一个非空白字符,在之前不能有其他语句;而且预处理器之后不能有其他与预处理

器不相关的语句,也就是非预处理器语句必须另起一行。本文把预处理器指令的语法都写在一行上,假设用户已做了正确的格式处理。

一、#define指令

1、#define指令格式:#define 标识符字符序列。比如#define N 3;

1)、表示以后凡是使用到“标识符”的地方都被后面的“字符序列”替换。注意该语句不以分号结束。

2)、编译器不会对“字符序列”进行类型检查。也就是说字符序列可以是任意的字符。

3)、语句中的字符序列可以是任意的字符序列,而不仅仅是数字,比如#define PI HYONG这样的话在使用PI时就

会用HYONG来替换掉PI,替换之后HYONG可能会是一个未定义的标识符。

2)、示例:#define N 3

1)、表示以后使用到符号PI时都会被置换为3,比如int a[N];定义大小为3的数组。

2)、虽然N看起来和变量一样,但N和变量没有任何关系,N只是一个符号或标志,在程序代码编译前该符号

会用一组指定的字符来替换。

3)、可以看到,N被3置换后,相当于拥有常量的性质,但在C++中最好是用const来声名常量,比如const long

double PI=3.1416;。

2、怎样把预处理指令放在多行上:其方法为使用续行符符号”\”,该符号应在上一行的最后一个字符。

比如#define m \

kkielfml

3、删除#define定义的标志的语法:#define 标识符

在#define语句中,不为标识符指定置换字符串就表示该标识符被删除了。比如#define PI表示在程序中该语句后面删除所有的PI标识符。比如int a=PI;则PI不会替换为任何东西,语句int a=PI相当于是int a=;所以程序出错。

4、使用#undef取消#define的定义的语法:#undef 标识符

表示取消在#undef后定义的“标识符。标识符被取消后,就不能再使用该标识符了。

5、带参数的#define的格式:#define 标识符(参数列表) 置换字符串

#define f(v) cout<<(v)<

6、重点:使用#define只能对标识符进行简单的置换,也就是他会将标识符直接替换为后面表示的字符序列,而不会

进行算术优先级或类型的检查。比如#define f(m,n) m*n 如果有调用f(4+2, 3);则该语句会被简单的替换为4+2*3这与我们所希望的(4+2)*3不一致,要解决这个问题就是给参数加上括号,比如#define f(m,n) (m)*(n)

8、使用字符串作为#define参数:比如#define m “kdi”如果有语句cout<

做#define m dki cout<<”m”;不能在标志符前加上双引号以试图输出字符串dki,这样只会输出字符串m,因为程序会把”m”解释为一个字符串,而不会把它解释为cout<<”dki”。

9、把#define参数指定为字符串:其方法是在参数前加上符号”#”,比如#define f(m) cout<<#m 如果这时有f(dikl);则程

序将会转换为cout<<”dikl”,最后输出字符串dikl。这里要注意的是该方法只能用于参数,而不能用于其他地方,比如#define m #kidkl这样就是错误的,这里试图用m来代替字符串”kidkl”,这是不成功的,正确方法为#define m “kidkl”

二、逻辑预处理器指令:

1、逻辑#if指令:该指令原理与条件语句if相同,如果测试为真就执行后面的语句,如果为假则跳过后面的语句。该

指令有两种用法,其一可以用#if指令测试某个符号以前是否用#define指令定义过,这是最常用的用法,其二可以用来测试某个条件表达式是否为真。

2、#if指令用法一:测试某个符号是否以前用#define定义过,共有以下几种情形

1)、#if指令语法形式一:

语法为: #if defined 标识符…. #endif //注意关键字defined比define多一个字母d。

缩写形式为:#ifdef 标识符….#endif

意义:表示如果指定的“标识符”已被#define定义,则中间的语句就包含在源文件中,如果该标识符还未被#define定义,则跳过#if和#endif之间的语句,该语句以#endif结束。

2)、#if指令语法形式二:

语法:#if !defined 标识符…..#endif //注意关键字defined比define多一个字母d。

缩写形式为:#ifndef 标识符…..#endif

意义:表示如果指定的标识符没有定义,则把#if和#endif之间的语句包含在源文件中,如果标识符已定义则跳过#if和#endif之间的代码,系统常使用该语句防止头文件被多次包含,

3)、示例1:#define N //定义标识符N,此例可以不需要指定值。

void main(){ //注意:预处理器指令必须作为第一个非空白字符,因此不能在”{“后使用预处理器指令。

#if defined N //若标识符N被定义则执行以下语句,注意预处理器指令结束后必须另起一行(即必须输入换行符)。

cout<<"A"<

#endif//注意:预处理器指令必须另起一行进行输入。

#ifndef N //若标识符N未被定义则执行以下语句

cout<<"B"<

#endif

} //注意:大括号必须另起一行,不能在#endif预处理器指令的后面

3、防止头文件被包含多次的语法:

#ifndef HY #define HY语句#endif //此处应使用正确的回车换行符

说明:程序在开始遇到标识符HY时没有被定义,这时执行后面的语句,并使用#define定义标识符HY,在第二次被使用时则标识符HY已经被定义,这时就不会执行后面的语句了,从而防止了同一头文件被包含多次的情

况。这里要注意,使用#define后面定义的标识符可以不需要值。

4、#if指令用法二:测试某个表达式的值是否为真,其语法格式为:#if 常量表达式….#endif,注意常量表达式的求值

结果应是整数常量表达式,比如#if a=2 …. #endif测试a的值是否为2,如果为2则执行#if与#endif之间的语句。

5、多个#if选择块:和常规的if语句一样#if也有对应的#else和#elif语句,比如#if a=3 …. #else …. #endif表示如果a=3

则执行if后面且在#else前面的语句,如果为假则执行#else与#endif间的语句。#elif用来实现多个选择,该语句和常规语句的else if相似,比如#if a=1 …. #elif a=2 …. #elif a=3…. #else …. #endif表示,如果a=1则执行#if后的语句,如果a=2则执行该条件后的语句。

三、RTTI运行时类型识别

使用以下函数需要包含头文件

注意:有些编译器需要把RTTI的特性打开才能使用,比如VC++2010就有这项设置,位于项目/属性然后展开C/C++选项卡选择“语言”,在右侧找到“运行时类型识别”,然后选是。

1、静态类型与动态类型:静态类型指的是对象(包括指针和引用)在声明时的类型,动态类型指的是当前对象(包括指针

和引用)实际指向的类型。比如B mb; A* p=&mb; 则p的静态类型是A*,而动态类型是B*,详见《C++继承,虚函数与多态性专题(修订版)》

2、RTTI运行时类型识别:使用运行时类型识别的主要作用是让我们能获得指向父类的指针实际所指向的子类的类型。

C++使用两个操作符来实现RTTI,即typeid和dynamic_cast,本小节介绍typeid操作符,dynamic_cast是强制类型转换运算符,位于下一小节。

3、typeid操作符形式:type_info& typeid(object) 其中object是任何类型的对象,也可以是一个类型。typeid反回type_info

类型的引用。

4、通过引用typeid反回的type_info的成员函数,可以使用typeid获得对象类型的名称、判断两个类型是否相等等操

作。详见下一条。

5、type_info类:

1)、type_info类的具体实现是依编译器而定的,不同编译器拥有不同的内容。

2)、type_info类的默认构造函数、复制构造函数和赋值操作符都是private私有的,因此不能创建、复制type_info

类型的对象,若要向type_info类中增加成员函数,则应该从type_info继承。

3)、程序中要引用type_info中成员函数的唯一方法是使用typeid反回的type_info类型的引用。

4)、type_info类的成员函数(重点):C++标准规定,所有编译器必须至少要实现以下成员函数:重载==操作符,重

载的!=操作符,成员函数name(),成员函数before(const type_info&),下面分别介绍这4个成员函数

①、重载的==和!=操作符用于判断两个类型是否相等,其中= =相等则反回true,!=不等反回true,比如

if(typid(3)!=typid(4.4))

②、name();成员函数:表示反回C风格字符串形式的类型名称,反回的称名依编译器而定,也就是说不同编译

器反回的名称可能会有一些不同。比如typeid(3).name();反回字符串”int”。

③、before成员函数主要是为了使type_info类的信息能够排序,因此意义不大。

6、使用typeid操作符

1)、cout<

2)、class A{}; cout<

3)、if(typeid(3)==typeid(4))cout<<”A”; //输出A,typeid比较和的类型,他们都是int型。

7、重点:只有当typeid的操作数是指向带有虚函数的类类型对象的指针时,且对该指针进行解引用后,才会反回指针

的动态类型,其余情况都是反回的指针的静态类型。

示例2:class A{public:virtual void f(){}}; class B:public A{}; B mb; A*pa=&mb;

cout<

cout<

示例3:class A{}; class B:public A{}; B mb; A* pa=&mb;

cout<

cout<

8、若指针p是指向带有虚函数类型的指针,且p=0;则typeid(*p)会抛出一个bad_typeid异常,typeid(p).name()仍然会得

到指针的静态类型。比如class A{public:virtual void f(){}}; class B{}; B mb; A*pa=0; 则typeid(*p).name();会抛出bad_typeid异常,需把该语句放入try块对异常做处理,否则是错误的。

9、若指针p指向的类型不带虚函数,且p=0;则typeid(*p).name();则反回指针的静态类型。

四、强制类型转换

1、强制类型转换运算符:C++有四种强制类型转换符,分别是dynamic_cast,const_cast,static_cast,reinterpret_cast。

其中dynamic_cast与运行时类型转换密切相关。使用这四种强制类型转换,主要是提高转换时的安全性,减少传统C语言强制转换时的随意性。

2、dynamic_cast强制转换运算符格式:dynamic_cast<目标类型>(表达式),//表示把表达式转换为尖括号中的目标类型

3、dynamic_cast转换符的作用:主要用于把父类类型的指针或引用转换为子类类型的指针或引用,以便能访问子类中

除了虚函数之外的其他特有成员,

示例4:class A{public:virtual void f(){}}; class B:public A{public: void g(){}}; A *pa=new B();

pa->g(); //错误,因为g不是虚函数也不是类A的成员函数

dynamic_cast(pa)->g(); //正确,表示把pa强制转换为子类B类型的指针,由此可以访问子类B中特有的成员。 4、使用dynamic_cast转换成功的条件(重难点):若被转换的指针或引用未指向或引用目标类型或目标类型的子类型,

则转换失败。若表达式所指向的对象不止一个表示目标类型的父类则转换也是失败的(此一点出现于多重继承时,详见后文示例11)

1)、若是使用dynamic_cast转换到指针类型时失败,则反回0。

2)、若是使用dynamic_cast转换到引用类型时失败,则抛出bad_cast类型的异常,该异常位于头文件

3)、理解dynamic_cast转换成功的条件(示例见下一条):比如:dynamic_cast(ma);则要求被转换的对象ma引

用目标类型B的对象,假设为B mb;即要求有形如:A& ma=mb;这样的语句,转换才能成功,当然若ma的类型就是B,则也能转换成功。注意A sa; A& ma=sa; B mb; ma=mb;并不是使ma重新引用mb,而是使用mb 对ma所引用的对象sa赋值。

5、dynamic_cast强制转换符的限制(重点)

1)、dynamic_cast被转换的对象必须是含有虚函数的类,因此内置类型间的转换是不允许的。

示例5:dynamic_cast(3.3);//错误,不能用于内置类型间的转换。

示例6:class A{}; class B:public A{}; A* pa=new B(); B *pb=dynamic_cast(pa);//错误,因为类A没有虚函数。

2)、dynamic_cast的目标类型必须是指针或引用。

示例7:class A{public:virtual void f(){}}; class B:public A{public: void g(){}}; A ma;

dynamic_cast(ma); //错误。目标类型B不是指针或引用

3)、除了满足前两个条件之外,被转换的指针必须要是已经初始化的,否则出错。

示例8:class A{public:virtual void f(){}}; class B:public A{public: void g(){}}; A *pa=0; A* pa1;

dynamic_cast(pa1);//错误。pa1未被初始化

B

*pb=dynamic_cast(pa);//正确,转换失败,结果为0,注意pa使用0初始化,也是初始化。

4)、dynamic_cast的目标类型可以不是多态的,在多重继承下比较明显。

示例9、class A{public:virtual void f(){}}; class B{public:void g(){cout<<"GB"<

class C:public A,public B{}; //类C同时继承自类B和类A,其中类B是非多态的。

C mc; A* pa=&mc;

dynamic_cast(pa); //正确,目标类型B可以不是多态的,但pa必须是多态的。

5)、若被转换的指针或引用未指向或引用目标类型或目标类型的子类型,则转换失败;因此被转换的对象就是目标

类型的对象,转换是能成功的。

示例10:class A{public:virtual void f(){}}; class B:public A{public: void g(){cout<<"A"<

A ma;

B mb; A ma1=mb; A &sa=mb; A &sa1=ma; A* pa=&ma; A* pa1=&mb; B* pb=&mb;

//dynamic_cast(ma); //错误,ma未引用目标类型B的对象,抛出bad_cast异常

dynamic_cast(mb); //正确,mb的类型就是目标类型B

//dynamic_cast(ma1); //错误,ma1未引用目标类型B的对象,抛出bad_cast异常

dynamic_cast(sa); //正确,sa引用了目标类型B的对象mb

//dynamic_cast(sa1); //错误,sa1引用的是类A的对象ma,ma不是目标类型B的对象。抛出bad_cast异常

cout<(pa)<

cout<(pa1)<

cout<(pb)<

6)、目标类型有多个时的转换失败,此时指针反回0,在多重继承时能表现出这种错误

示例11:class A{public:virtual void f(){}};

class B:public virtual A{public:}; //B虚拟继承自A,因此A只会有一个副本

class C:public B{}; //非虚拟继承,本例会存在类B的两个副本

class D:public B{}; //非虚拟继承,本例会存在类B的两个副本

class E:public D,public C{};

E me; A* pa=&me;

cout<(pa); //输出0,转换失败,因为存在两个B的副本。

6、由以上各点可看出dynamic_cast操作符在转换时执行两层检测,第一次检测转换是否有效,比如转换的目标类型是

否是指针等,若转换有效才进行转换,第二层检测发生在运行时刻,比如对指针转换失败反回0,对引用转换失败抛出bad_cast异常。

7、const_cast操作符格式:const_cast<目标类型>(表达式),//表示把表达式转换为尖括号中的目标类型

作用:该操作符用于改变const和volatile限定符(增加或删除),const_cast最常用的用途就是删除const属性,如果某个变量在大多数时候是常量,而在某个时候又是需要修改的,这时就可以使用const_cast操作符了。比如int a=3; const int *p=&a; 则*p=4;错误,但*const_cast(p)=4;正确,cout<<*p; 输出4。

8、const_cast操作符的限制

1)、const_cast操作符只能改变const或volatile限定符(增加或删除),不能对其他类型进行转换,即const_cast不能

进行从int到double的转换等。比如int a=4; int *p=&a; 则const_cast(p); 错误。

2)、const_cast只能用于指针或引用。比如const int a=3; 则const_cast(a);错误。

9、static_cast操作符:static_cast<目标类型>(表达式);该操作符用于非多态类型的转换,任何标准转换都可以使用他,

即static_cast可以把int转换为double,但不能把两个不相关的类对象进行转换,比如类A不能转换为一个不相关的类B类型。static_cast本质上是传统c语言强制转换的替代品。

10、reinterpret_cast操作符格式:reinterpret_cast<目标类型>(表达式)

1)、要明白此操作符的函数,需要明白内存与类型的解释,请看本节最后或《C++指针与数组专题》

2)、目标类型必须是一个指针、引用、整型(包括所有int型、char型、bool型、枚举型)

3)、reinterpret_cast可以实现从整型到指针,从指针到整型,从一个指针到其他任意指针间的相互转换。

4)、深入理解reinterpret_cast操作符(难点):reinterpret_cast操作符可以用来处理与类型无关的转换,转换后的值

与原始表达式所表示的值有完全相同的比特位。说简单一点,就是对内存中的比特位重新赋予了一种类型或者说对比特位重新进行解释。因此这种转换是很危险的,需要小心使用。比如假设在内存中的比特位为0111 1111 0100 0110,若这串比特位按int型解释,那就是十进制数的32582,若按char型解释则因为char只占一个字节,因此只能解释8位,假设解释的是最后8位,则0100 0110=70,相当于char型的字符F,那么假设有int a=32582;

则char c=reinterpret_cast(a);则cout<(a)表示把存储在内存中a的值的比特位按char型进行解释,结果就是字符F。

5)、为什么reinterpret_cast可以在任意指针之间相互转换:因为指针类型占据的内存宽度都是一样(一般为4字节),

因此指针之间是可以相互转换的,指针指向的类型只影响指针解释的内存的宽度,但对指针本身没有影响,比如假设int *p指向位置0000 0001(16进制),因为p是int型(假设占4字节),因此*p会解释4字节的内容假设为0000 0001~0000 0004; 若p是float型,即float *p;同样指向位置0000 0001,假设float占8字节,因此*p会解释8字节的内容,假设为0000 0001~0000 0008,此处可见,对于指针是int型还是float型,对指针本身p指向的位置没有影响,int和float只影响指针对内存中的内容怎样解释。

java对象转换String类型的三种方法

北大青鸟中关村 java对象转换String类型的三种方法在很多情况下我们都需要将一个对象转换为String类型。一般来说有三种方法可以实现:Object.toString()、(String)Object、String.valueOf(Object)。下面对这三种方法一一分析 一、采用Object.toString() toString方法是https://www.doczj.com/doc/ad14579855.html,ng.Object对象的一个public方法。在java中任何对象都会继承Object 对象,所以一般来说任何对象都可以调用toString这个方法。这是采用该种方法时,常派生类会覆盖Object里的toString()方法。 但是在使用该方法时要注意,必须保证Object不是null值,否则将抛出NullPointerException 异常。 二、采用(String)Object 该方法是一个标准的类型转换的方法,可以将Object转换为String。但是在使用该方法是要注意的是需要转换的类型必须是能够转换为String的,否则会出现CalssCastException异常错误。 代码代码如下: Object o = new Integer(100); String string = (String)o; 这段程序代码会出现https://www.doczj.com/doc/ad14579855.html,ng.ClassCastException: https://www.doczj.com/doc/ad14579855.html,ng.Integer cannot be cast to https://www.doczj.com/doc/ad14579855.html,ng.String。因为将Integer类型强制转换为String类型,无法通过。 三、String.valueOf(Object) 上面我们使用Object.toString()方法时需要担心null问题。但是使用该方法无需担心null值问题。因为在使用String.valueOf(Object)时,它会判断Object是否为空值,如果是,则返回null。下面为String.valueOf(Object)的源码: 代码代码如下: public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); } 从上面我们可以看出两点:一是不需要担心null问题。二是它是以toString()方法为基础的。但是一定要注意:当object为null时,String.valueOf(object)的值是字符串对象:"null",而不是null!!!

C语言中的强制类型转换运算

C语言中的强制类型转换运算 C语言中的强制类型转换是通过类型转换运算来实现的。 其一般形式为: (类型说明符)(表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。 例如: (float)a 把a转换为实型 (int)(x+y)把x+y的结果转换为整形 在使用强制转换时应注意以下问题: 1)类型说明符和表达式都必须加括号(单个变量可以不加括号),如果把(int)(x+y)写成(int)x+y则成了把x转换成int型之后再与y相加了。 2)无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性的转换,而不改变数据说明时对该变量定义的类型。 【例1】 #include int main (void) { float f = 3.14; printf("(int)f = %d,f = %.2f\n",(int)f,f); return 0; } 本例表明,f虽强制转为int型,但只在运算中起作用,是临时的,而f本身的类型并不改变。因此,(int)f的值为5(删去了小数)而f的值仍为5.75. 1、求余运算符(模运算符)“%”:双目运算,具有左结合性。要求参与运算的量均为整型。求余运算的结果等于两数相除后的余数。 #include int main (void) { printf(" %d\n",110%3);

return 0; } 本例输出110除以3所得的余数2。 2、算数表达式和运算符的优先级和结合性 表达式是由常量、变量、函数和运算符组合起来的式子。一个表达式有一个值及其类型,他们等于计算表达式所得结果的值和类型。表达式求值按运算符的优先级和结合性规定的顺序进行。单个的常量、变量、函数可以看作是表达式的特例。 算数表达式是由算术运算符和括号连接起来的式子。 算数表达式:用算数运算符和括号将运算对象(也称操作数)连接起来的、符合C语法规则的式子。 以下是算数表达式的例子: a+b; (a*2)/c; (x+r)*8-(a+b)/7; ++I; Sin(x)+sin(y); (++i)-(j++)+(k--); 运算符的优先级:C语言中,运算符的运算优先级共分为15级。1级最高,15级最低。在表达式中,优先级较高的先于优先级较低的进行运算。而在一个运算量两侧的运算符优先级相同时,则按运算符的结合性所规定的结合方向处理。 运算符的结合性:C语言中各运算符的结合性分为两种,即左结合性(自左至右)和右结合性(自右至左)。例如算术运算符的结合性是自左至右,即先左后右。如有表达式x-y+z,则先执行x-y运算,然后再执行+z运算。这是左结合性。右结合性最典型的是赋值运算符。如x=y=z. 3、强制类型转换运算符 其一般形式为: (类型说明符)(表达式)

halcon知识点

1. 无论读入什么图像,读入图像显示效果明显和原始图像不一致,哪怕是从相机读入的图像,也是明显颜色差异。什么原因引起? 初步诊断是,显示的时候调用的颜色查找表存在异常不是 default ,而是其它选项。此时可以通过查阅相关参数,调用set_system解决,也可以在编辑-》参数选择-》颜色查找表进行更改。 2. 裁剪图像;从图像上截取某段图像进行保存。如何实现该操作? 首先应该知道,region不具有单独构成图像的要素,他没有灰度值。有用过opencv的应该知道 ROI(感兴趣区域),设置好它后,对图像的大部分操作就转为图像的一个矩形区域内进行。类似的,halcon有domain 概念。首先设置好一个矩形区,然后使用 reduce_domain(是一个矩形区域)后,再使用crop_domain 就裁剪出图像。 3. 读入bmp,或tiff 图像显示该图不是bmp文件或不能读。原因是什么? 这个常有新手询问,画图,图像管理器都能打开,又或者是相机采集完直接存到硬盘。Halcon 读取图像在windows下面到最后是调用windows库函数实现读图功能。咱不清楚到底是怎么调用的。对于图像格式,在读图函数F1说明很细。基本 bmp 如果文件头不是bw还是bm(百度百科bmp格式查找,编写此处时无网络,后续可能忘记),就读不进来。其他规格欢迎补充。解决办法,如果是相机采集,就在内存直接转换(参见 halcon到VC.pdf 里面的halcon和bitmap互转);如果是采完的图片,大部分通过画图工具转换为 24位bmp格式,即可解决。 4.读入avi文件报错。

Halcon 通过 directshow或另一个格式解析视频,正常来说应该可以读入市面大部分视频,实际测试发现只能读入最标准的avi文件格式。如果需要临时处理,需要下格式工厂等工具转化为最标准的avi文件格式(论坛叶诺有发帖说明)。 5. Region 或 xld 筛选。 Halcon提供了丰富的region 和xld筛选方法。Region可以使用select_shape_xld,选择出符合要求的区域,如果不能满足还可以通过类似 region feature 这样关键字组合成的算子获取区域特征,然后通过 tuple 排序或相加减,再通过 tuple_find 确定是对应哪个区域的特征。同样的halcon也提供了 select_contours_xld 进行轮廓筛选。 6. Halcon分几类对象,每个类的功用是? Halcon总分俩大类,tuple和图标对象obj 。Tuple涵盖了对所有基础数据类型的封装,可以理解为她是halcon定义的数组类。Obj 是alcon定义图标类基类。衍生出了许多类型,其中 Region ,Xld,Image 其中最主要的类型。 7. F1说明,参数部分 -array 是什么意思? 该符号说明,该参数接受一组输入,对tuple就是一组tuple,对obj 就是通过concat_obj 或其它操作产生的一组obj元组。 8. 俩个相对方形物体的距离计算。 如果这俩个物体和背景对比清晰,最近的距离在俩条边下则可以再预处理之后进行如下操作:

强制类型转换及指针本质

强制类型转换类型的本质指针的本质函数指针 昨天给朋友讲了 3个问题, A〉什么是函数指针,本质是?指针的本质? B〉什么是类型,类型的本质是? C〉什么是强制类型转换,本质是? 作者张世光亿通科技软件部 060913 QQ:87895224 MSN:Z_55@https://www.doczj.com/doc/ad14579855.html, A〉什么是函数指针,本质是?指针的本质? 如 void fun(); //函数声明 void (*ptrfun)();//函数指针变量ptrfun 的声明,表明ptrfun这个指针指向一个 void fun()函数类型的函数地址。 〉函数的名字代表函数的地址; 所以,可以这样 ptrfun =fun ;//给ptrfun赋值。此时,ptrfun 就是 fun 函数的别名; 在需要调用 fun()的地方,可以这样写 (*ptrfun)(); //等同于 fun(); //这就是别名的意义。 指针的本质是一个固定长度(32位系统上是4个byte)的空间中放置的内容是一个内存地址。 而指针类型的本质就是对这个地址的解释方式。不同的指针类型,对即使相同的内存地址的解释是不同的,受影响的空间大小也不同。受影响的空间的大小等于sizeof(类型)。 如 short i=0x1234; short * psort = &i; char *pchar = &i; //此时 pshort ==pchar;即指向了同一个地址; 那么 (*pshort) 和 (*pchar) 的值各是什么? 假设 sizeof(short)==2 sizeof(char)==1 假如内存中这样: ---地址 0x1000-- | 0x34 | ---------------- | 0x12 | ---------------- 那么,psort==0x1000 ,同时,pchar==0x1000 ; 那么,(*psort) 代表是地址0x1000 和 0x1001 这两个字节的内容; <-----由其类型决定 (*pchar)代表地址0x1000 这一个字节的内容; <<-----由其类型决定

C++强制类型转换

关于强制类型转换的问题,很多书都讨论过,写的最详细的是C++ 之父的《C++ 的设计和演化》。最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_cast, dynamic_cast。标准C++中有四个类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。下面对它们一一进行介绍。 static_cast 用法:static_cast < type-id > ( expression ) 该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法: ?用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。 ?用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。 ?把空指针转换成目标类型的空指针。 ?把任何类型的表达式转换成void类型。 注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。 dynamic_cast 用法:dynamic_cast < type-id > ( expression ) 该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果ty pe-id是一个引用,那么expression也必须是一个引用。 dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

Java中常见异常类型及分析

Java常见异常类型及原因分析 这里介绍几种常见的异常并对原因进行分析,包括: ●NullPointException异常; ● ClassCastException异常; ● ArrayIndexOutOfBoundsException异常; ●UnsupportedClassVersionError错误; ●NumberFormatExceptio异常 ●堆栈溢出和内存溢出。 1 NullPointException异常 顾名思义,NullPointerException是空指针异常。但是在Java中没有指针,怎么会有空指针异常呢? 在C++中,声明的指针需要指向一个实例(通过new方法构造),这个指针可以理解为地址。 在Java中,虽然没有指针,但是有引用(通常称为对象引用,一般直接说对象),引用也是要指向一个实例对象(通过new方法构造)的,从这种意义上说,Java中的引用与C++中的指针没有本质的区别,不同的是,处于安全的目的,在Java中不能对引用进行操作,而在C++中可以直接进行指针的运算,例如book++等。 所以这里的NullPointerException虽然不是真正的空指针异常,但本质上差不多,是因为引用没有指向具体的实例,所以当访问这个引用的方法的时候就会产生这种异常。例如下面的代码: String str = "这是一个测试用的字符串!"; System.out.println(str.length()); 这段代码没有问题,但是如果改成下面的代码: String str ; System.out.println(str.length()); 就会产生NullPointerException异常了,当然一般人不会犯这样低级的错误。 那这种异常通常是如何产生的呢?比较多见的是下面的两种情况: 1)把调用某个方法的返回值直接赋值给某个引用,然后调用这个引用的方法。在这种情况下,如果返回的值是null,必然会产生NullPointerException异常。例如: String userName=request.getParameter("userName"); if(userName.length()==0) ...... else ...... 如果request.getParameter("userName")的结果为null,则这里就会产生这种异常。 2)在方法体中调用参数的方法。这种情况下,如果调用方法的时候传递进来的值是null,也要产生NullPointerException异常。 要解决这种异常,只需要检查异常出现在第几行(通常在集成开发环境中会提示用户错误发生在第几行),然后查看调用了哪个对象的方法,然后检查这个对象为什么没有赋值成

全国计算机等级考试二级C语言真题题库3+2015年9月

全国计算机等级考试二级C语言真题题库3 2015年9月 (总分:43.00,做题时间:120分钟) 一、选择题(每小题1分,共40分)(总题数:40,分数:40.00) 1.下列叙述中正确的是()。 (分数:1.00) A.程序可以作为算法的一种表达方式√ B.算法的有穷性是指算法的规模不能太大 C.算法的复杂度用于衡量算法的控制结构 D.算法的效率与数据的存储结构无关 解析:[解析]算法的有穷性是指操作步骤有限且能在有限时间内完成,如果一个算法执行耗费的时间太长,即使最终得出了正确结果,也是没有意义的,故B选项错误。一个算法复杂度的高低体现在运行该算法所需要的计算机资源的多少,故C选项错误。算法的效率是指算法执行的时间,算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量,这就与算法本身设计的优劣以及具体的编程实现有关,数据的存储结构会极大的影响程序的执行时间,故D选项错误。算法在实现时需要用具体的程序设计语言来实现,所以程序可以作为实现算法的一种表达方式。故选A选项。 2.某循环队列的存储空间为Q(1:m),初始状态为front=rear=m。现经过一系列的入队操作和退队操作后,front=m-1,rear=m,则该循环队列中的元素个数为()。 (分数:1.00) A.m-1 B.1 √ C.m D.0 解析:[解析]循环队列长度为m,由初始状态为front=rear=m可知此时循环队列为空。入队运算时,首先队尾指针(rear)进1(即rear+1),然后在rear指针指向的位置插入新元素。特别的,当队尾指针rear =m+1时,置rear=1。迟队运算时,排头指针(front)进1(即front+1),然后删除front指针指向的位置上的元素,当排头指针front=m+1时,置front=1。从排头指针front指向的后一个位置直到队尾指针rear指向的位置之间所有的元素均为队列中的元素,则该循环队列中的元素个数为m-(m-1)=1。故选择B 选项。 3.能从任意一个节点开始没有重复地扫描到所有节点的数据结构是()。 (分数:1.00) A.循环链表√ B.双向链表 C.二叉链表 D.有序链表 解析:[解析]在单链表的第一个节点前增加一个表头节点,队头指针指向表头节点,最后一个节点的指针域的值由NULL改为指向表头节点,这样的链表称为循环链表。在循环链表中,只要指出表中任何一个节点的位置,就可以从它出发没有重复地扫描到表中其他所有的节点。双向链表与二叉链表都可以扫描到所有节点,但是会有重复。有序链表如果是单链表的情况下,不能扫描到所有节点。故A选项正确。 4.某棵树中共有25个节点,且只有度为3的节点和叶子节点,其中叶子节点有7个,则该树中度为3的节点数为()。 (分数:1.00) A.不存在这样的树√ B.7 C.8 D.6 解析:[解析]树是一种简单的非线性结构,直观地来看,树是以分支关系定义的层次结构。在树结构中,一个节点所拥有的后件个数称为该节点的度,所有节点中最大的度称为树的度。首先假设这样的树是存在

简析JAVA中int、String间类型转换

初学Java,对于类型转换以及强制类型转换还是没什么难度的,但是初学者往往在涉及到String类型的转换时,就会抛出问题了。这里收集整理了下,仅供参考。 int 转String int i=12345; String s=”"; 第一种方法:s=i+”"; 第二种方法:s=String.valueOf(i); 这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? String转int s=”12345″; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法:i=Integer.valueOf(s).intValue(); 这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? 以下是答案:

3.) String s = “” + i; 注: Double, Float, Long 转成字串的方法大同小异. JAVA数据类型转换这是一个例子,说的是JAVA中数据数型的转换.供大家学习package shenmixiaozhu; import java.sql.Date; public class TypeChange { public TypeChange() { } //change the string type to the int type public static int stringToInt(String intstr) { Integer integer; integer = Integer.valueOf(intstr); return integer.intValue(); } //change int type to the string type public static String intToString(int value) { Integer integer = new Integer(value); return integer.toString(); } //change the string type to the float type public static float stringToFloat(String floatstr) { Float floatee; floatee = Float.valueOf(floatstr); return floatee.floatValue(); } //change the float type to the string type public static String floatToString(float value) { Float floatee = new Float(value); return floatee.toString(); } //change the string type to the sqlDate type public static java.sql.Date stringToDate(String dateStr) { return java.sql.Date.valueOf(dateStr); } //change the sqlDate type to the string type

halcon基础数据类型详解

halcon基础数据类型详解 #if defined(__CHAR_UNSIGNED__) || defined(__sgi) #define INT1 signed char /* integer, signed 1 Byte */ #define INT1_MIN SCHAR_MIN #define INT1_MAX SCHAR_MAX #else #define INT1 char /* integer, signed 1 Byte */ #define INT1_MIN CHAR_MIN #define INT1_MAX CHAR_MAX #endif #define UINT1 unsigned char /* integer, unsigned 1 Byte */ #define UINT1_MIN 0 #define UINT1_MAX UCHAR_MAX #define LONG_FORMAT _INT64_FORMAT typedef INT4_8 Hlong; typedef UINT4_8 Hulong; 看粗体部分,可以看到Hlong型在32位的机器上其实就是long型代表4个字节32位,在64位机器上有另一种定义 再来看看halcon中最重要的数据类型HTuple,在C++里面,halcon将HTuple类型封 装了类,其始祖类HRootObject,这个类相当于MFC里面的CObject,halcon从HRootObject 派生了HBaseArray,当然这两个类是虚基类,有一些方法需要我HTuple自己实现,当然也 有一些方法可以直接用的。这两个类在HCPPUtil里,可以看看。 HTuple类就是从HBaseArray派生,元组基类,相当于数组,具有如下的构造函数: HTuple(int l); HTuple(float f); HTuple(double d); HTuple(constchar *s);

int.parse和强制类型转换的区别

c#中(int)、int.Parse()、int.TryParse、Convert.ToInt32的区别收藏 以前经常为这几种数据类型转换方式而迷茫,这次为了彻底搞清它们之间的区别和优缺点,在网上查看了一些资料,并亲自验证了一下,在此写出来,一方面,为那些跟我有过相似经历的朋友们些许,另一方面,希望前辈们指导一下,看哪里有不合适的地方。 1 (int)变量名[强制类型转换]: 该转换方式主要用于数字类型转换,从int类型到long,float,double,decimal类型,可以使用隐式转换,但是从long类型到int类型就需要使用显式转换,也就是该数据类型转换方式,否则会产生编译错误。 该方式对于浮点数会做无条件舍去,失去精确度 当然,该方式也可以进行object到int得转换,但是,object的值要赋予int类型的值,否则会产生编译错误,而且object为null时也会出错。 最后切忌的一点,千万不要用来处理char类型到int类型的转换,否则传回的的值是ASCII代码,而并不是你想要的值。 2 int.Parse(string类型变量名) 该方式是将数字内容的字符串转为int类型,如果字符串内容为空或者null时,则抛出ArgumentNullException异常;如果字符串内容不是数字,则抛出FormatException异常;如果字符串内容所表示数字超出int类型可表示的范围,则抛出OverflowException异常。 使用该方法切忌的一点就是只能处理字符串内容,而且字符串内容只能在int类型可表示的范围之内。 3 int.TryParse(string s, out int result) 该方式也是将数字内容的字符串转为int类型,但是该方式比int.Parse优越的地方,就是它不会出现异常。如果转换成功返回true,如果转换失败返回false。很明显,最后一个参数为输出值,如果转换失败,输出值为0;如果转换成功,则输出相应的值。 4 Convert.ToInt32 该方式不仅可以将字符串转为int类型,还可以将其它类型的值转成int类型。变量若为object或string类型,当其值为null时,会传回0,不会造成程序错误,但是若此string类型的值为string.Empty,在转型成int时,仍会造成程序错误。 该方式对于浮点数会做四舍五入。 该方式同强制转换一样,不能用来处理char类型,否则传回的是ASCII代码。

Halcon

Halcon 目录 1、相机接入且拍摄 (2) 1.1 步骤 (2) 1.2 后续处理函数 (5) 2、相机标定 (7) 2.1标定步骤 (7) 3、手眼系统标定 (11) 3.1 标定步骤 (11) 4、图像坐标和机器臂坐标转换 (13) 4.1 转换步骤 (14) 5、模版匹配(基于形状) (19) 5.1 步骤 (19) 6、常见函数 (25) 6.1 图像分割 (25) 6.2 轮廓提取、处理 (31)

1、相机接入且拍摄 1.1 步骤 (1)连接相机 open_framegrabbe(Name, HorizontalResolution, VerticalResolution, ImageWidth, ImageHeight, StartRow, StartColumn, Field, BitsPerChannel, ColorSpace, Generic, ExternalTrigger, CameraType, Device, Port, LineIn, AcqHandle) 在算子窗口内输入函数名,填入参数后点击“确定”按钮即可将函数加入程序中。 注: Name: 图像采集设备的名称 可通过以下步骤确定: 1、在Halcon菜单栏里点击“窗口”,选择“打开算子窗口”。 (若算子窗口已打开则直接进入第二步) 2、在“输入算子或函数”栏内输入“open_framegrabbe” 回车后出现下图

3、在“参数”栏中的Name后点击即可自动检测连接的设 备(笔记本电脑摄像头检测后为’DirectShow’) 此参数若随意填写,可能导致程序报错 HorizontaResolution、VerticalResolution:预期的图像采集接口的水平分辨率和垂直分辨率 ImageWidth、ImageHeight:预期图像的宽度和高度部分StartRow、StartColumn:显示预期图像的开始坐标 Field:预期图像是一半的图像或者是完整图像 BitsPerChannel:每像素比特数和图像通道 ColorSpace:获取图像的输出形式(gray、raw、rgb、yuv、default)说明:此参数设置不同的值可以得到不同的图像效果,如设置

C语言中不同的结构体类型的指针间的强制转换详解

C语言中不同类型的结构体的指针间可以强制转换,很自由,也很危险。只要理解了其内部机制,你会发现C是非常灵活的。 一. 结构体声明如何内存的分布, 结构体指针声明结构体的首地址, 结构体成员声明该成员在结构体中的偏移地址。 变量的值是以二进制形式存储在内存中的,每个内存字节对应一个内存地址,而内存存储的值本身是没有整型,指针,字符等的区别的,区别的存在是因为我们对它们有不同的解读,param的值就是一个32位值,并且存储在某个内存单元中,通过这个32位值就能找到param所指向的结构的起始地址,通过这个起始地址和各个结构所包含变量离起始地址的偏移对这些变量进行引用, param->bIsDisable只是这种引用更易读的写法,只要param是指向 PAINT_PARAM的指针,那么param的值就肯定存在,param存在,偏移量已知,那么param->bIsDisable就肯定存在,只是要记住,param->bIsDisable只是代表了对param一定偏移地址的值。 不是说某个地址有那个结构体你才能引用,即使没有,你也能引用,因为你已经告诉了编译器param变量就是指向一个PAINT_PARAM结构体的变量并且指明了param的值,机器码的眼中是没有数据结构一说的,它只是机械的按照 指令的要求从内存地址取值,那刚才的例子来说,peg->x,peg->y的引用无论 0x30000000是否存在一个eg结构体都是合法的,如果0x30000000开始的8 个字节存在eg结构体,那么引用的就是这个结构体的值,如果这个位置是未定义的值,那么引用的结果就是这8个字节中的未定义值,内存位置总是存在的,而对内存中值的引用就是从这些内存位置对应的内存单元取值。 举个例子: typedefstruct_eg { int x; int y; }eg;

Java(1-4)复习题

《使用Java理解程序逻辑》1-4章阶段测试 一课后选择题 二、选择题 1、下列语句中,( BD )正确完成整形变量的声明和赋值。 A). int count,count=0; B). int count=0; C). count=0; D). int count1=0,count2=1; 2、在JAVA中,用于向控制台打印输出信息的语句是(A)。 A). System.out.println() B). System.println() C). Out.println() D). Print.println() 3、给定某Java程序的main方法如下所示,该程序的运行结果是( A)。Public static void main(String[] args){ int i=0; System.out.println(i ); } (选择一项)A A). 输出0 B). 输出1 C). 编译错误 D). 运行时出现异常 4、在Java 中,下列代码的远行结果是(D )。 public static void main(String[] args) { int a=1,b=2,c=3; if(a<0) if(b<0) c=10;

c=20; System.out.println(c); } A). 输出:10 B). 输出:20 C). 输出:3 D). 编译报错 5、在Java中,源文件Test.java中包括如下代码段,则程序编译运行结果是(b)。 public class Test{ public static void main(String[]args){ system.out.print(“Hello!”); } } A). a) 输出:Hello! B). b) 编译出错,提示“无法解析system” C). c) 运行正常,但没有输出任何内容 D). d) 运行时出现异常 6、在Java中,Scanner类提供从控制台获取键盘输入的功能,下列语句( b)能够正确实例化Scanner类的对象,用于获得键盘输入的数据。 A). Scanner input = new Scanner(System.out) B). Scanner input = new Scanner(System.in) C). Scanner input = new Scanner(System) D). Scanner input = new Scanner() 7、下面程序的执行结果是( c) public class Weather { public static void main(String[] args) { int shiDu=45; if(shiDu>=80){ System.out.println("要下雨了"); }else if(shiDu>=50){ System.out.println("天很阴"); }else if(shiDu>=30){ System.out.println("很舒适"); }else if(shiDu>=0){ System.out.println("很干燥");

halcon学习笔记——实例篇 长度和角度测量+

halcon学习笔记——实例篇长度和角度测量实例二:长度和角度测量 素材图片: halcon代码: 1: *读取并截取图片 2: dev_close_window() 3: read_image (Image, 'D:/MyFile/halcon/长度和角度测量/图.png') 4: crop_rectangle1 (Image, ImagePart, 75, 0, 400, 400) 5: get_image_size (ImagePart, Width, Height) 6: dev_open_window (0, 0, Width, Height, 'black', WindowHandle) 7: dev_display (ImagePart) 8: 9: *获取图形的边界 10: threshold (ImagePart, Regions, 0, 112) 11: 12: *分离三角形和圆形

13: connection(Regions,ConnectedRegions) 14: sort_region(ConnectedRegions,SortedRegions,'upper_left','true','column') 15: select_obj(SortedRegions,Circle,1) 16: select_obj(SortedRegions,Triangle,2) 17: 18: *获取三角形各边的信息 19: skeleton(Triangle,TriangleSkeleton) 20: gen_contours_skeleton_xld(TriangleSkeleton,TriangleContours,1,'filter') 21: segment_contours_xld(TriangleContours,ContoursSplit,'lines_circles', 5, 4, 2) 22:select_contours_xld(ContoursSplit,SelectedContours, 'contour_length',100, 999, -0.5, 0.5) 23: fit_line_contour_xld (SelectedContours, 'tukey', -1, 10, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist) 24: 25: *计算三角形角度 26:angle_ll (RowBegin[0], ColBegin[0], RowEnd[0], ColEnd[0], RowBegin[1], ColBegin[1], RowEnd[1], ColEnd[1], Angle1) 27:angle_ll (RowBegin[0], ColBegin[0], RowEnd[0], ColEnd[0], RowBegin[2], ColBegin[2], RowEnd[2], ColEnd[2], Angle2) 28:angle_ll (RowBegin[1], ColBegin[1], RowEnd[1], ColEnd[1], RowBegin[2], ColBegin[2], RowEnd[2], ColEnd[2], Angle3) 29: Angle1:=abs(deg(Angle1)) 30: Angle2:=abs(deg(Angle2)) 31: Angle3:=abs(deg(Angle3)) 32: 33: *获取圆的信息 34: area_center(Circle,AreaCircle, RowCircle, ColumnCircle) 35: 36: *计算圆心到三角形各边的距离 37: Distance := [] 38:for Index := 0 to 2 by 1 39:distance_pl (RowCircle, ColumnCircle, RowBegin[Index], ColBegin[Index], RowEnd[Index], ColEnd[Index], ThisDistance) 40: Distance := [Distance,ThisDistance] 41: endfor

C语言类型强制转换

C语言类型强制转换 本篇主要介绍 C语言类型强制转换。 强制类型转换是通过类型转换运算来实现的。其一般形式为:(类型说明符)(表达式)其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。 自动转换是在源类型和目标类型兼容以及目标类型广于源类型时发生一个类型到另一类的转换。例如: (float) a 把a转换为实型(int)(x+y) 把x+y的结果转换为整型在使用强制转换时应注意以下问题: 1.类型说明符和表达式都必须加括号(单个变量可以不加括号),如把(int)(x+y) 写成(int)x+y则成了把x转换成int型之后再与y相加了。 2.无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进 行的临时性转换,而不改变数据说明时对该变量定义的类型。 例1: main() { float f=5.75; printf("(int)f=%d,f=%f\n",(int)f,f); } f<--5.75 将float f强制转换成int f float f=5.75;printf("(int)f=%d,f=%f\n",(int)f,f); 本例表明,f虽强制转为int 型,但只在运算中起作用,是临时的,而f本身的类型并不改变。因此,(int)f 的值为 5(删去了小数)而f的值仍为5.75。 例2:比如我们可以(int)'A',这样转换后的结果为A的ASCII码数值,因为那块内存本来就存的那个数,只是换个形式使用而已。知道上面的原则,我们 可以对任何数据类型进行转换,但是转换的结果可能不是你想像的结果,举例 (int)'9'的结果为多少?不是9而是0x39。来个高深点的printf("%d",'12'); 的输出是什么?正确答案是12594,因为printf("%d",'12'),打印的是存储12 的内存地址上的内容,即ASCII码值2存储在低位,1储在高位地址,0x32就是2 的ASCII码,0x31就是1的ASCII码,所以是0x3132,转换成10进制就是12594!

Java语言基本数据类型、转换及其封装

Java语言基本数据类型、转换及其封装Java语言基本数据类型、转换及其封装 1. 逻辑类型 ·常量 true,false。 ·变量的定义 使用关键字boolean来定义逻辑变量: boolean x; boolean tom_12; 也可以一次定义几个: boolean x,tom,jiafei,漂亮 x,tom,jiafei,漂亮都是变量的名字。定义时也可以赋给初值: boolean x=true,tom=false,漂亮=true,jiafei 2.整数类型 ·常量123,6000(十进制),077(八进制),0x3ABC(十六进制)。 ·整型变量的定义分为4种: 1.int 型 使用关键字int来定义int型整形变量 int x int tom_12 也可以定义几个: int x,tom,jiafei,漂亮 x,tom,jiafei,漂亮都是名字。定义时也可以赋给初值: int x=12,tom=-1230,漂亮=9898,jiafei 对于int型变量,分配给4个字节byte,一个字节由8位(bit)组成,4个字节占32位(bit)。bit 有两状态,分别用来表示0,1。这样计算机就可以使用2进制数来存储信息了。内存是一种特殊的电子元件,如果把内存条放大到摩天大

楼那么大,那么它的基本单位——字节,就好比是大楼的房间,每个房间的结构都是完全相同的,一个字节由8个能显示两种状态的bit组成,就好比每个房间里有8个灯泡,每个灯泡有两种状态——亮灯灭灯。 对于 int x=7; 内存存储状态如下: 00000000 00000000 00000000 00000111 最高位:左边的第一位,是符号位,用来区分正数或负数,正数使用原码表示,最高位是0,负数用补码表示,最高位是1。例如: int x=-8; 内存的存储状态如下: 11111111 11111111 11111111 11111000 要得到-8的补码,首先得到7的原码,然后将7的原码中的0变成1,1变成0,就是-8的补码。 因此,int型变量的取值范围是-2^31~2^31-1。 2. byte型 使用关键字byte来定义byte型整型变量 byte x ; byte tom_12; 也可以一次定义几个: byte x,tom,jiafei,漂亮 x,tom,jiafei,漂亮都是名字。定义时也可以赋给初值: byte x=-12,tom=28,漂亮=98,jiafei 注:对于byte型变量,内存分配给1个字节,占8位,因此byte型变量的取值范围是: -2^7~2^7-1。

Halcon学习2_图形图像数据结构

1·Image 在Halcon中,Image=Channel+Domain,其中,像素点放在channel矩阵中,根据ROI对Image进行描述。 2·Region 为某些符合要求性质的像素子集,或者说一些被选择的图块区域s,region大小不受图像限制,有fill和margin两种表达方式,可用于压缩。 *选择相应区域 select_shape(regions,output,'select type',..requirements) *计算相应区域的面积,中心坐标 area_center(regions,area,row,column) *不规则区域的转换 shape_trans(region,regiontrans,type) 3·图型变量XLD(eXtended Line Descriptions) XLD代表亚像素级别的轮廓或者多边形 *XLD的选择操作 select_shape_xld(XLD : SelectedXLD : Features, Operation, Min, Max : ) select_contours_xld(Contours : SelectedContours : Feature, Min1, Max1, Min2, Max2 : ) *计算xld的面积以及中心位置 //area_center_xld(XLD:::Area,row,column,pointOrder) *Xld 的拟合操作(fit_***_contour_xld) 把不完整的形状拟合完整 fit_line_contour_xld fit_circle_contour_xld fit_ellipse_contour_xld fit_rectangle2_contour_xld 4·读取照片方法 a·申明一个数组,分别保存路径 ImagePath:=[] ImagePath[0]:='D:/1.bmp' ImagePath[1]:='D:/2.bmp' ImagePath[2]:='D:/3.bmp' for i:=0 to 2 by 1 read_image(Image,ImagePath[i]) endfor

相关主题
文本预览