为了验证指针加减运算时是移动一个字节还是移动指针所指向数据类型的字节长度。我们用一下程序即可验证。
1 int a = 0;
2 int* pa = &a;
3
4 printf("%d \n",(int)pa);
5 pa ++ ;
6 printf("%d \n",(int)pa);
7 printf("int %d %d \n",(int)pa,(int)(pa++));
对于char型指针,执行 pa++ 后,其地址增加1,对于int型指针,执行 pa++ 后,其地址增加4。(编程环境:32位操作系统。VS2010)
由此可知 指针加减运算移动单位为指针所指向数据类型的字节长度。
遇到的问题 :
以上程序的输出为:
由第7行的输出可知:printf入栈为自右往左, (int)(pa++) 先将参数入栈,再++,而后在对(int)pa入栈时,之前以++过一次,所以输出结果如上。
若将第7行代码改为 printf("int %d %d \n",(int)pa,(int)(++pa)); 则输出为 X,X+4,X+8,X+8。原理同上。
更进一步的看一个例子:
int arr[]={6,7,8,9,10};
int *ptr=arr;
printf("%d,%d,%d",*ptr,*(++ptr),*(ptr--));
在WIN32 VS2010中输出结果为:6,6,6
其原理为:先执行最右边的参数入栈,及 *(ptr),然后执行ptr- -;再执行中间参数入栈,及 ptr + +,然后*(ptr);最后执行最左边的参数入栈,及*(ptr)。所以结果为6,6,6.
但有人说这个执行顺序与编译器和环境相关。本人尚未测试,有兴趣的可以自行测试。以上数据测试环境皆在 WIN32 VS2010中所得。如有疑问,可以共同探讨。
续0:
int arr[]={6,7,8,9,10};
int *ptr=arr;
printf("%d,%d",*(++ptr),*(ptr));
同一环境下,输出结果为:7,7。
若 用上面的原理解释,答案应该为7,6。实际结果与之前解释的相悖。求大神们指点。
续1:
若将一指针进行,强制转换,这指针的寻址是按照原来的类型还是转换后的类型:
char bbb[4]="0000";
int aaa = 0xf11ff22f;
int *abc = &aaa;
bbb[0] = ((char *)abc)[0];
bbb[1] = ((char *)abc)[1];
bbb[2] = ((char *)abc)[2];
bbb[3] = ((char *)abc)[3];
printf("%d %d %d %d\n",bbb[0],bbb[1],bbb[2],bbb[3]);
输出结果:47 -14 31 -15;
以十六进制表示下列数 0x2f 0xf2 0x1f 0xf1
若将输出改为以十六进制输出:
printf("%x %x %x %x\n",bbb[0],bbb[1],bbb[2],bbb[3]);
则输出结果为:2f fffffff2 1f fffffff1
由上结果可以知道,指针强制转换后,寻址按照转换以后的类型进行寻址。即 int * 变为 char * 后,指针加1时,只移动1个字节。
对于 %x的输出,因为其默认为整型数的输出,所以负数高位全为1,所以 -14的输出为 fffffff2。
在此基础上,联想到opencv 中IplImage的数据赋值问题。imageData指针类型为char *;
1.对于IPL_DEPTH_8U的图像数据来说,取值和赋值都很简单,直接按字节进行赋值或取值即可,注意自动填充的冗余字节数。
2.对于不是IPL_DEPTH_8U的图像数据。例如IPL_DEPTH_16U。
当赋值时,将原始 short 类型的数据指针强制转换为char*,逐个字节赋值即可。
当取值时,直接将char * imageData 强制装换为 short * ,逐点赋值即可。