c++对象模型笔记:指针类型转换

来源:互联网 发布:希特勒经济政策 知乎 编辑:程序博客网 时间:2024/06/05 05:38
这篇笔记说的是关于c/c++中的类型转换的东西,重点是与指针有关的类型。

1、强制类型转换

看一下这个c代码:

int a = 0x123456;  //0x是十六进制的表示法
char c = (char)a;
printf("%d/n", c);

在我的编译环境里输出的是什么呢? 是86,怎么得来的呢?(我的编译环境见“概述”)

int a的内存如下(左边是低地址的内容,右边是高地址的内容):0x56  0x34  0x12 0x00

"是不是搞反了?" 有人奇怪(正如我当年~~~~~~),这个问题还得详细讨论,但不是在这里,是在别的文章,上google搜一下“little endian”,看一下相关的知识,然后再回来看啊。(我用的是intel x86系列的cpu,所以是little endian序的)

(little endian序的内容就是:低字节数据放入低地址,高字节数据放入高地址,比如上面的56是低字节,所以放入低地址)

现在转换到char,char在我的环境里占一字节,(char)a的意思就是,取a中的第一个字节出来,就是0x56了(5 * 16 + 6 = 86)

这就是c语言中基本类型的强制类型转换。

(不知道上面的方法给了你什么启发,比如下面的问题:编写一个c程序,判断你用的机子是little endian还是big endian,你想到思路了吗?呵呵)

那么,如果是自定义类型的类型转换会如何呢?

比如:

struct A
{
    int a;
};

struct B
{
   char c;
};

struct A aA;
aA.a = 0x123456;
printf( "%d/n", ( (struct B)aA ).c);

很遗憾,这个是通不过编译的,为什么呢?

原因可能如下(是我猜测的,如有不正确之处,各位指点一下,谢谢):

基本类型是编译器定义的,所以编译器里面也实现了关于基本类型的转换函数,比如(int)a,实际上是在编译期间,在编译器的内部调用了相关的转换函数,所以就编译通过。

但是我们自定义的类型,编译器里面没有相关的转换函数,所以就转换不了。

为了弥补这个缺陷,c++中提供了一种转换运算符的重载,只要重载转换运算符(),就可以实现自定义类型之间的类型转换了。(关于转换运算符重载的用法,去google吧,我以前也没用过,只是知道有这个东西而已,呜呜~)

2、关于指针的类型转换的含义

那么,到底有没有办法能实现以上的功能呢?能~!用指针类型转换就能!

下面还是从基本类型开始:

int a = 0x123456;

int *pa = &a;

char *ca = (char *)pa;

printf("%d/n", *ca);

答案呢?还是86,呵呵~(原理和上面的一样,这里就不重复了)

所以我个人怀疑,基本类型的运算符的强制转换操作在编译器内部还是通过指针来实现的(个人猜测,如有不正确之处,请多多指教,谢谢)

所有的指针变量的大小都是固定的,都是4字节(再次注意这一系列的笔记的所有例子有一个大的前提,就是我的编译环境,请看笔记之“概述”)。

那么,指针变量定义时候,前面的类型说明什么呢?既然int *pInt; 和char *pChar;中,pInt和pChar的大小都是4字节,那么,int和char在这里的作用又是干嘛的?

休息一下,下面请看“指针类型转换的基本原理”。

...(唱个“对面的女孩看过来”先)

......

指针定义的时候,前面的类型声明,说明的是指针所指向变量。具体一点,是所指向的变量在内存的大小(sizeof()可以算出来),进一步可以推算出,该指针变量一次操作说取的内存单位。

比如

int a = 0x123456;
int *pInt = &a;

那个int *就说明了pInt指向的类型是一个整形,这意味着:pInt每次操作时候,以4字节为单位,就是说每次4字节4字节的取内存;所以pInt指向的是a的地址(里面从低到高放着:0x56, 0x34,0x12, 0x00...),读取4字节,再注意到这是little endian序,*pInt就是0x00123456了。

如果是 short *pShort = (short*)&a;呢?

(shrot *)&a说明了,取a的地址,放到pShort变量中去,而pShort的类型声明是short,也就是说每次是以内存的2字节为单位,是2字节2字节的取数据,每次pShort+1其实是在内存里面向高处移动2字节。

*pShort = 多少呢? 是0x3456(过程和上面的相似,这里不重复了)

那么对于自定义类型的指针转换可以嘛?下面试试例子吧。

struct A
{
   int a;
};

struct B
{
   char c;
};

struct A aA;
struct B *pB;
aA.a = 0x123456;
pB = (struct B*)&aA;
printf("%d/n", pB->c);

编译通过...连接通过...执行结果是86,Oh,Yeah!大功告成,亲亲嘴儿...(谁拍我的脸~)

转换的过程这里就不重复了。

所以说一般的类型转换是有限的,但指针的类型转换却是无限的~(你可以这样称呼它:黑客的宠儿~~)

好了,这篇笔记到这里就差不多结束了,下面再记下几个问题:

1、是我以前在某公司的面试题目,问的是expr的值

char str[] = "abcdefghigklmn";
char expr = *(char*)( (int*)(str + 3) + 1 );

2、是我在工作当中遇到的一个问题的简化。

char str[] = "abcdefg";
short *pStr = (short *)str;
printf("%d/n", *pStr);

问输出什么?

这个背景是要建立一个哈希表,其索引是字符串的头两个字节,所以就有了这个东东~

PS.

本来我想写简练一点的,但是没办法,水平就这个样子,以后在写的过程中我会慢慢的改正一些风格的,希望各位能做一些评论,谢谢。

本笔记其实就说了一件事,指针定义的类型说明的作用就是:该变量指向的内存空间的大小和一次操作的单位。
原创粉丝点击