xyjzsh

c++编程习惯(1)

1.尽量使用一个构造函数。
原因:如果使用多个构造函数,可能导致在有很多个实例变量的时候没有在所有的构造函数中初始化,从而造成错误!
可以用默认值的方法来达到提供默认构造函数。
2.在考虑跨平台时要尽量不使用int,unsigned系列的类型,因为不同平台对它们所占的字节数不一定相同。
3.技巧:使用
do
{
}while(0);
这样就可以在合适的时候break。然后在while后面做最后的处理。
class A
{
.....
};

4.对于数组初始化时可以用
A arr[10]={0};
或者memset(arr,0,sizeof(arr));
而尽量不要使用memset(arr,0,10*sizeof(A));
在用第二种方法memset(arr,0,10*sizeof(A))时在A的名称变化或者数组大小变化的时候都要修改。
但要特别注意
如果 A *a = new A[10];
就一定要用memset(a,0,10*sizeof(A));因为a是指针,所以sizeof(a)为4。


posted @ 2010-11-23 11:41 呆人 阅读(557) | 评论 (2)编辑 收藏

KMP算法的一点理解

KMP算法是在给定的字符串中查找某一特定的字符串(我们称之为模式串(Pattern)).
时间复杂度是O(m+n):m是模式串的字符数,n是给定的目标串的长度。
在写自己见解之前,先给大家一个Martrix67大牛的关于KMP算法的一个链接
http://www.matrix67.com/blog/archives/115

我认为KMP算法的难点在于当匹配失效时,我们要将模式串的第几个字符与当前目标串的失效处进行比较。

我们用T来表示目标串,P(m)来表示有m个字符的模式串。
已知P[1...q] 与 T[s+1,s+2,....s+q]匹配。而P[q+1] 不等于T[s+q+1];
那么T[s+q+1]应该和P的哪个字符进行比较呢?

由P[1..q] = T[s+1,...s+q]对应相等,假设T[s+q+1]要和P[k+1]进行比较(我们是基于1的字符串,即第一个字符我们用1而不是0来表示它的下标。)
那么我们必须保证
P[1...k] = T[ s+q-k+1...,s+q].
因为在一定之前P[1...q] = T[s+1,...s+q];所以P[q-k+1...q] = T[s+q-k+1,...,s+q];
P[q-k+1,...,q]是P从q之前的k个字符,即P[q]的后面k字符。
P[1...k]是P的前k个字符。
所以当我们在P[q+1]和T[s+q+1]不匹配时,
我们就是找到最大的k,使得前k个字符和后k个字符相等。

代码如下:

 


long IndexOfSubString(LPCTSTR source,unsigned int start,LPCTSTR subStr)
{
    
long sourceLen = _tcslen(source);
    
long subLen = _tcslen(subStr);
    
    
long *helpArr = new long[subLen];
    memset(helpArr,
0,sizeof(long)*subLen);
    
    helpArr[
0=-1;

    
long index(0);
    
long j(-1);
    
for(index=1;index<subLen;index++)
    
{
        
while(j>0 && subStr[index] !=subStr[j+1]) j = helpArr[j];

        
if(subStr[index] == subStr[j+1])
            j
++;

        helpArr[index] 
= j;
    }


    j
=-1;
    
for(index=start;index<sourceLen;index++)
    
{
        
while(j>-1&&source[index] !=subStr[j+1]) j=helpArr[j];

        
if(source[index] == subStr[j+1])
            j
++;
        
if(j==subLen-1)
         
return index-j;
    }

    delete[] helpArr;
    
return -1;
}



posted @ 2010-11-23 11:08 呆人 阅读(199) | 评论 (0)编辑 收藏

在vs2008中调整lib文件输出的位置【转】

在vs2008中调整lib文件输出的位置

默认分类 2010-05-06 13:32:38 阅读94 评论0   字号: 订阅

选择“项目->属性”弹出项目属性页对话框,选择“配置属性->链接器->高级”在其中的“导入库”中设置相对路径即可。注意:相对路径写在第一个$符号的前面。如:..\..\dist\lib\debug\$(TargetName).lib

如下图:

在vs2008中调整lib文件输出的位置 - danshiming - danshiming的博客

posted @ 2010-11-19 13:35 呆人 阅读(1156) | 评论 (0)编辑 收藏

c++的类型转换interpret_cast,static_cast,dynamtic_cast,const_cast【转载】

C++的四种cast操作符的区别--类型转换

C++的四种cast操作符的区别
发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内

声明 by NetMD:
并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样才比较完备

----------------------------------------------------------------------

Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意?

A:转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式。为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符。比如,为了转换一个类型为doubole的浮点数的指针到整型:
代码:
int i;
double d;

i = (int) d;
或者:

i = int (d);

对于具有标准定义转换的简单类型而言工作的很好。然而,这样的转换符也能不分皂白的应用于类(class)和类的指针。ANSI-C++标准定义了四个新的转换符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast',目的在于控制类(class)之间的类型转换。
代码:
reinterpret_cast<new_type>(expression)
dynamic_cast<new_type>(expression)
static_cast<new_type>(expression)
const_cast<new_type>(expression)


1 reinterpret_cast

'reinterpret_cast'转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型。反之亦然。(译注:是指针具体的地址值作为整数值?)
这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。

如果情况是从一个指针到整型的拷贝,内容的解释是系统相关的,所以任何的实现都不是方便的。一个转换到足够大的整型能够包含它的指针是能够转换回有效的指针的。

代码:
class A {};
class B {};

A * a = new A;
B * b = reinterpret_cast<B *>(a);
'reinterpret_cast'就像传统的类型转换一样对待所有指针的类型转换。

2 static_cast

'static_cast'允许执行任意的隐式转换和相反转换动作。(即使它是不允许隐式的)

应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。

在这最后例子里,被转换的父类没有被检查是否与目的类型相一致。
代码:
class Base {};
class Derived : public Base {};

Base *a    = new Base;
Derived *b = static_cast<Derived *>(a);
'static_cast'除了操作类型指针,也能用于执行类型定义的显式的转换,以及基础类型之间的标准转换:

代码:
double d = 3.14159265;
int    i = static_cast<int>(d);

3 dynamic_cast

'dynamic_cast'只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:
class Base { virtual dummy() {} };
class Derived : public Base {};

Base* b1 = new Derived;
Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1);          // succeeds
Derived* d2 = dynamic_cast<Derived *>(b2);          // fails: returns 'NULL'

如果一个引用类型执行了类型转换并且这个转换是不可能的,一个bad_cast的异常类型被抛出:
代码:
class Base { virtual dummy() {} };
class Derived : public Base { };

Base* b1 = new Derived;
Base* b2 = new Base;

Derived d1 = dynamic_cast<Derived &*>(b1);          // succeeds
Derived d2 = dynamic_cast<Derived &*>(b2);          // fails: exception thrown

4 const_cast

这个转换类型操纵传递对象的const属性,或者是设置或者是移除:
代码:
class C {};

const C *a = new C;

C *b = const_cast<C *>(a);
其它三种操作符是不能修改一个对象的常量性的。
注意:'const_cast'也能改变一个类型的volatile qualifier。

--------------------------------------------------------------------

C++的4种类型转换

    一、C 风格(C-style)强制转型如下:

    (T) expression // cast expression to be of type T
    函数风格(Function-style)强制转型使用这样的语法:
    T(expression) // cast expression to be of type T
    这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型。

   二、 C++的四种强制转型形式:

  C++ 同时提供了四种新的强制转型形式(通常称为新风格的或 C++ 风格的强制转型):
  const_cast(expression)
  dynamic_cast(expression)
  reinterpret_cast(expression)
  static_cast(expression)

  每一种适用于特定的目的:

  ·dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
    
    ·static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换。
    
  ·const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。

  ·reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。
  
  旧风格的强制转型依然合法,但是新的形式更可取。首先,在代码中它们更容易识别(无论是人还是像 grep 这样的工具都是如此),这样就简化了在代码中寻找类型系统被破坏的地方的过程。第二,更精确地指定每一个强制转型的目的,使得编译器诊断使用错误成为可能。例如,如果你试图使用一个 const_cast 以外的新风格强制转型来消除常量性,你的代码将无法编译。

==  
==  dynamic_cast .vs. static_cast
==

class B { ... };
class D : public B { ... };

void f(B* pb)
{
   D* pd1 = dynamic_cast<D*>(pb);
   D* pd2 = static_cast<D*>(pb);
}

If pb really points to an object of type D, then pd1 and pd2 will get the same value. They will also get the same value if pb == 0.

If pb points to an object of type B and not to the complete D class, then dynamic_cast will know enough to return zero. However, static_cast relies on the programmer’s assertion that pb points to an object of type D and simply returns a pointer to that supposed D object.

    即dynamic_cast可用于继承体系中的向下转型,即将基类指针转换为派生类指针,比static_cast更严格更安全。dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性.static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换,窄化变换(这种变换会导致对象切片,丢失信息),用VOID*的强制变换,隐式类型变换等...


==
==  static_cast .vs. reinterpret_cast
==

    reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它.我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的.(这句话是C++编程思想中的原话)

    static_cast 和 reinterpret_cast 操作符修改了操作数类型. 它们不是互逆的; static_cast 在编译时使用类型信息执行转换, 在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的. 另一方面, reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换, 例子如下:

    int n=9; double d=static_cast < double > (n);

    上面的例子中, 我们将一个变量从 int 转换到 double. 这些类型的二进制表达式是不同的. 要将整数 9 转换到 双精度整数 9, static_cast 需要正确地为双精度整数 d 补足比特位. 其结果为 9.0. 而reinterpret_cast 的行为却不同:

    int n=9;
    double d=reinterpret_cast<double & > (n);

    这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析.

posted @ 2010-11-15 15:01 呆人 阅读(1519) | 评论 (0)编辑 收藏

printf中变参的实现

#ifdef _M_CEE_PURE
typedef System::ArgIterator va_list;
#else
typedef char *  va_list;
#endif /* _M_CEE_PURE */

我们使用 typedef char* va_list;//va_list是一个指向char的函数指针

#define _ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )
_ADDRESSOF(v)的作用是取得v变量的地址。

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
以int所占的字节为标准进行对其操作。
如果int占四字节,则以四字节对齐为标准读取数据。

在stdarg.h中有下面三个宏的定义
#define va_start
_crt_va_start
#define va_arg
_crt_va_arg
#define va_end
_crt_va_end
红色标注的宏是用户直接使用的宏,下面我们来看一下他们各自的实现,即绿色标注的部分。

在vadefs.h中有上述绿色标注部分的实现。

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

解析
1.   #define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
(va_list)_ADDRESSOF(v)得到v的地址
INTSIZEOF(v) 字节对齐后v的大小
最后ap指向v的下一个对象的指针,即所以ap 就指向v后面的参数的起始地址。

2.#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
分为以下几个step解析:
(1) ap += _INTSIZEOF(t) 指向类型为t的下一个参数的地址。
(2) (ap += _INTSIZEOF(t))- _INTSIZEOF(t) 指向当前类型为t的参数的指针
(3)(t*)((ap += _INTSIZEOF(t))- _INTSIZEOF(t))将当前指针转换成t类型的指针
(4)( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取得当前指针的值。

3.#define _crt_va_end(ap)      ( ap = (va_list)0 )
将va_list置成无效指针。

以上是printf()变参的实现过程







posted @ 2010-11-11 17:25 呆人 阅读(486) | 评论 (0)编辑 收藏

printf的实现【转载】

va_list,va_start,va_arg,va_end——变长参数实现机制
2009年10月28日 星期三 11:09 P.M.

什么是变长参数?

所谓含有变长参数的函数是指该函数可以接受可变数目的形参。例如我们都非常熟悉的

printf,scanf等等。

2:变长参数如何实现?

首先来看下面这样一个例子:

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

void demo(char *msg,...)
{
va_list argp;
int arg_number=0;
char *para = msg;
va_start(argp,msg);
while(1)
{
   if ( strcmp( para, "\0") != 0 )
   {
    arg_number++;   
    printf("parameter %d is: %s\n",arg_number,para);
   
   }
   else
    break;
   para = va_arg(argp,char *);
}
va_end(argp);
}
int main()
{
demo("Hello","World","\0");
system("pause");
return 0;
}

实现这样一个函数要在内部使用va_list,va_start,va_arg,va_end,这些都是定义在

stdarg.h中的宏。

va_list是定义了一个保存函数参数的数据结构。

va_start(argp,msg)是将argp指向第一个可变参数,而msg是最后一个确定的参数。

最后一个确定的参数的含义是指它以后的参数都是可变参数,如果有下面的函数声明

void demo(char *msg1,char *msg2,...)

那么这里的最后一个确定参数就是msg2。

va_arg(argp,char *)返回当前参数的值,类型为char *,然后将argp指向下一个变长参

数。从这一步可以看出来我们可以通过va_start和va_arg遍历所有的变长参数。

va_end 将argp的值置为0。


下面我们看看上述几个宏在visual c++.net 2003 中的实现方法。首先是va_list的实现

#ifdef   _M_ALPHA
typedef struct {
         char *a0;        /* pointer to first homed integer argument */
         int offset;      /* byte offset of next parameter */
} va_list;
#else
typedef char *   va_list;
#endif


可以看到va_list实际上是一个机器类型相关的宏,除了alpha机器以外,其他机器类

型都被定义为一个char类型的指针变量,之所以定义为char *是因为可以用该变量逐

地址也就是逐字节对参数进行遍历。

从上面可以看到,这些宏的实现都是和机器相关的,下面是大家常用的IX86机器下宏的

相关定义。

#elif    defined(_M_IX86)

#define _INTSIZEOF(n)    ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v)   ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)       ( ap = (va_list)0 )

#ifdef   __cplusplus
#define _ADDRESSOF(v)    ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v)    ( &(v) )
#endif

首先看_INTSIZEOF(n)

我们知道对于IX86,sizeof(int)一定是4的整数倍,所以~(sizeof(int) - 1) )的值一定是

右面[sizeof(n)-1]/2位为0,整个这个宏也就是保证了右面[sizeof(n)-1]/2位为0,其余位置

为1,所以_INTSIZEOF(n)的值只有可能是2,4,8,16,......等等,实际上是实现了字节对齐。

#define va_start(ap,v)   ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

所以va_start(ap,v)的作用就很明了了,_ADDRESSOF(v)定义了v的起始地址,_INTSIZEOF(v)定义了v所

占用的内存,所以ap 就指向v后面的参数的起始地址。

#define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

ap += _INTSIZEOF(t) 使ap指向了后面一个参数的地址

而( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )相当于返回了目前t类型的参数的值。

#define va_end(ap)       ( ap = (va_list)0 )

将变量ap 的值置为0。

通过上述分析,再次印证了我么前面对可变参数实现的解释。


因此我们可以总结出变长参数函数的一般实现方法:

1:声明原型,形如void demo(char *msg,...),注意变长参数的原型声明中至少要含有

一个确定参数。

2:用va_list定义保存函数参数的数据结构,可以理解为一个指针变量(稍后会解释)。

3:用va_start将上一步定义的变量指向第一个可变参数。

4:用va_arg遍历所有的可变参数。

5:用va_end将指针变量持有的地址值置为0。


posted @ 2010-11-11 17:23 呆人 阅读(1806) | 评论 (0)编辑 收藏

c++类型转换操作【转载】

C++的四种cast操作符的区别--类型转换

C++的四种cast操作符的区别
发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内

声明 by NetMD:
并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样才比较完备

----------------------------------------------------------------------

Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意?

A:转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式。为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符。比如,为了转换一个类型为doubole的浮点数的指针到整型:
代码:
int i;
double d;

i = (int) d;
或者:

i = int (d);

对于具有标准定义转换的简单类型而言工作的很好。然而,这样的转换符也能不分皂白的应用于类(class)和类的指针。ANSI-C++标准定义了四个新的转换符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast',目的在于控制类(class)之间的类型转换。
代码:
reinterpret_cast<new_type>(expression)
dynamic_cast<new_type>(expression)
static_cast<new_type>(expression)
const_cast<new_type>(expression)


1 reinterpret_cast

'reinterpret_cast'转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型。反之亦然。(译注:是指针具体的地址值作为整数值?)
这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。

如果情况是从一个指针到整型的拷贝,内容的解释是系统相关的,所以任何的实现都不是方便的。一个转换到足够大的整型能够包含它的指针是能够转换回有效的指针的。

代码:
class A {};
class B {};

A * a = new A;
B * b = reinterpret_cast<B *>(a);
'reinterpret_cast'就像传统的类型转换一样对待所有指针的类型转换。

2 static_cast

'static_cast'允许执行任意的隐式转换和相反转换动作。(即使它是不允许隐式的)

应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。

在这最后例子里,被转换的父类没有被检查是否与目的类型相一致。
代码:
class Base {};
class Derived : public Base {};

Base *a    = new Base;
Derived *b = static_cast<Derived *>(a);
'static_cast'除了操作类型指针,也能用于执行类型定义的显式的转换,以及基础类型之间的标准转换:

代码:
double d = 3.14159265;
int    i = static_cast<int>(d);

3 dynamic_cast

'dynamic_cast'只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:
class Base { virtual dummy() {} };
class Derived : public Base {};

Base* b1 = new Derived;
Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1);          // succeeds
Derived* d2 = dynamic_cast<Derived *>(b2);          // fails: returns 'NULL'

如果一个引用类型执行了类型转换并且这个转换是不可能的,一个bad_cast的异常类型被抛出:
代码:
class Base { virtual dummy() {} };
class Derived : public Base { };

Base* b1 = new Derived;
Base* b2 = new Base;

Derived d1 = dynamic_cast<Derived &*>(b1);          // succeeds
Derived d2 = dynamic_cast<Derived &*>(b2);          // fails: exception thrown

4 const_cast

这个转换类型操纵传递对象的const属性,或者是设置或者是移除:
代码:
class C {};

const C *a = new C;

C *b = const_cast<C *>(a);
其它三种操作符是不能修改一个对象的常量性的。
注意:'const_cast'也能改变一个类型的volatile qualifier。

--------------------------------------------------------------------

C++的4种类型转换

    一、C 风格(C-style)强制转型如下:

    (T) expression // cast expression to be of type T
    函数风格(Function-style)强制转型使用这样的语法:
    T(expression) // cast expression to be of type T
    这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型。

   二、 C++的四种强制转型形式:

  C++ 同时提供了四种新的强制转型形式(通常称为新风格的或 C++ 风格的强制转型):
  const_cast(expression)
  dynamic_cast(expression)
  reinterpret_cast(expression)
  static_cast(expression)

  每一种适用于特定的目的:

  ·dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
    
    ·static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换。
    
  ·const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。

  ·reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。
  
  旧风格的强制转型依然合法,但是新的形式更可取。首先,在代码中它们更容易识别(无论是人还是像 grep 这样的工具都是如此),这样就简化了在代码中寻找类型系统被破坏的地方的过程。第二,更精确地指定每一个强制转型的目的,使得编译器诊断使用错误成为可能。例如,如果你试图使用一个 const_cast 以外的新风格强制转型来消除常量性,你的代码将无法编译。

==  
==  dynamic_cast .vs. static_cast
==

class B { ... };
class D : public B { ... };

void f(B* pb)
{
   D* pd1 = dynamic_cast<D*>(pb);
   D* pd2 = static_cast<D*>(pb);
}

If pb really points to an object of type D, then pd1 and pd2 will get the same value. They will also get the same value if pb == 0.

If pb points to an object of type B and not to the complete D class, then dynamic_cast will know enough to return zero. However, static_cast relies on the programmer’s assertion that pb points to an object of type D and simply returns a pointer to that supposed D object.

    即dynamic_cast可用于继承体系中的向下转型,即将基类指针转换为派生类指针,比static_cast更严格更安全。dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性.static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换,窄化变换(这种变换会导致对象切片,丢失信息),用VOID*的强制变换,隐式类型变换等...


==
==  static_cast .vs. reinterpret_cast
==

    reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它.我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的.(这句话是C++编程思想中的原话)

    static_cast 和 reinterpret_cast 操作符修改了操作数类型. 它们不是互逆的; static_cast 在编译时使用类型信息执行转换, 在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的. 另一方面, reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换, 例子如下:

    int n=9; double d=static_cast < double > (n);

    上面的例子中, 我们将一个变量从 int 转换到 double. 这些类型的二进制表达式是不同的. 要将整数 9 转换到 双精度整数 9, static_cast 需要正确地为双精度整数 d 补足比特位. 其结果为 9.0. 而reinterpret_cast 的行为却不同:

    int n=9;
    double d=reinterpret_cast<double & > (n);

    这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析.

posted @ 2010-11-11 16:51 呆人 阅读(173) | 评论 (0)编辑 收藏

c++中各操作符优先级一览表【转载】

C语言程序设计 运算符的优先级与结合性

 C运算符的优先级与结合

优先级

运算符

含义

参与运算对象的数目

结合方向

 1

( )
[ ]
->
.

圆括号运算符
下标运算符
指向结构体成员运算符
结构体成员运算符


双目运算符
双目运算符
双目运算符

自左至右

2


~
++
--
-
(
类型)


sizeof

逻辑非运算符
按位取反运算符
自增运算符
自减运算符
负号运算符
类型转换运算符
指针运算符
取地址运算符
求类型长度运算符

单目运算符

自右至左

3


/
%

乘法运算符
除法运算符
求余运算符

双目运算符

自左至右

4


加法运算符
减法运算符

双目运算符

自左至右

5

<<
>>

左移运算符
右移运算符

双目运算符

自左至右

6

<
<=
>
>=

关系运算符

双目运算符

自左至右

7

==
!=

判等运算符
判不等运算符

双目运算符

自左至右

8

按位与运算符

双目运算符

自左至右

9

按位异或运算符

双目运算符

自左至右

10

|

按位或运算符

双目运算符

自左至右

11

&&

逻辑与运算符

双目运算符

自左至右

12

||

逻辑或运算符

双目运算符

自左至右

13

?:

条件运算符

三目运算符

自右至左

14


+=
-=
*=
/

%

>>=
<<=
&=
=
|

赋值运算符

双目运算符

自右至左

15

逗号运算符
(顺序求值运算符)

 

自左至右

















































posted @ 2010-11-11 10:51 呆人 阅读(544) | 评论 (0)编辑 收藏

编译项目跟踪文档(三)

这里主要写一下“-”的处理。
词法分析阶段,我们可以把“-”解释成减号或者是表示是一个负数
那么怎么来区分这两种情况呢?
我的做法(有点投机取巧,个人感觉不是很好,可是又想不出更好的来,希望大家能给我更好的建议):

词法分析阶段,将所有所得的单词(Token)放到 m_tokens[]中。

如果碰到"-",将他解析成__SUB__TOKEN(减号),放到m_tokens[index1] = __SUB__TOKEN;

解析到数字单词(__NUM_TOKEN)时,判断它的前一个单词是否是__SUB__TOKEN.

1.如果是__SUB__TOKEN,则判断__SUB__TOKEN的前一个单词是否是(算术运算符:+,-,*,/以及是否是(,{,=)(*)
    
    1.1如果(*)中的任意一个则将前一个__SUB__TOKEN识别成负号,把当前的__NUM__TOKEN的值取反,并用__NUM_TOKEN覆盖它前面的__SUB_TOKEN.

    1.2 如果不是(*)中的任意一个,则认为前一个__SUB_TOKEN就是减号。

2.如果不是__SUB__TOKEN,不予处理。

不知道我又没有表述清楚,本来有一个流程图,可是不知道怎么贴过来,见谅!! 

posted @ 2010-11-05 09:18 呆人 阅读(169) | 评论 (0)编辑 收藏

编译项目跟踪文档(二)

今天发现了自己一直都理解错的一个问题:逻辑运算符的优先级问题。
取反的优先级最高
&&的优先级次之
||的优先级最低。

今天要将循环语句翻译成中间代码。由于一直没有找到很明确的关于条件表达式的语法定义。在此将自己定义的语法结构记下啦,希望大家多多指教:

IF(BoolExp)
{
  StmtSequence
}
ELSE
{
   StmtSequence
}

BoolExp ----> BoolTerm |  || BoolTerm
BoolTerm ----> BoolFactor | && BoolFactor
BoolFactor ----> (BoolExp) | RelExp | !BoolExp

RelExp ----> ArithExp relOp ArithExp
ArithExp ----> ArithTerm | +ArithTerm | -ArithTerm
ArithTerm ----> ArithFactor | *ArithFactor | /ArithFactor
ArithFactor -----> ID | NUM| Func| (ArithExp)

relOp ----->  > | >= | < |<= | == | !=

StmtSequence -> Stmt | ;Stmt
Stmt -> AssignStmt | DeclareStmt | ConditionalStmt | CallFuncStmt
至于更细节的地方在此不做赘述。

对于结构产生式的左边每一个非终结符有一个对应的方法。根据语法定义调用即可。
如果需要代码请留言,并注明邮箱,发给你!!

生成控制流代码时采用回填技术。我觉得龙书《Compilers,Principles,Techniques,&Tools 》second Editon对于回填技术讲的很清楚。



posted @ 2010-11-02 16:10 呆人 阅读(1322) | 评论 (1)编辑 收藏

仅列出标题
共6页: 1 2 3 4 5 6 
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜