指標加減運算和printf輸出與自加自減運算順序
為了驗證指標加減運算時是移動一個位元組還是移動指標所指向資料型別的位元組長度。我們用一下程式即可驗證。
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 * ,逐點賦值即可。