他の言語では強制型変換がありますが、式の方法は異なりますが、規則は同じです。つまり、大から小までは強制変換を必要としません。大から小までは強制型変換を必要とします。実際、型変換は単純です1つのデータ型の変数を別の型の変数に変換するために使用されます。
コードに直接:
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
pの値が0x100000であるとします。次の表の式の値は何ですか?
p + 0x1 = 0x___ ?
(unsigned long)p + 0x1 = 0x___?
(unsigned int*)p + 0x1 = 0x___?
多くの人はこの質問の意味を最初は理解していないと思います。実際、これが少しなじみのあるものかどうかを詳しく見てみましょう。ポインター変数と整数を解析する方法は?
以前の "a + 1"と "&a + 1"の違いを覚えていますか?実はここも同じです。整数へのポインター変数の加算および減算は、ポインター変数内のアドレスで整数を直接加算または減算することではありません。この整数の単位はバイトではなく、要素の数です。
つまり、p + 0x1の値は0x100000 + sizof(Test)* 0x1です。この構造のサイズは20バイトなので、ここでは詳しく説明しません。したがって、p + 0x1の値は0x100014です。
(unsigned long)p + 0x1の値はどうですか?これには、ポインタ変数pに格納されている値を符号なしlong整数に強制変換する強制が含まれます。値が強制されると、その型が変更されます。したがって、この式は実際には符号なし長整数と別の整数です。したがって、その値は0x100001です。
(unsigned int *)p + 0x1の値はどうですか?ここのpは、符号なし整数へのポインターに強制変換されます。したがって、その値は0x100000 + sizof(unsigned int)* 0x1であり、0x100004と同じです。
強制型変換の別の例について話しましょう。
intmain()
{
int a[4]={
1,2,3,4};
int *ptr1=(int *)(&a+1);//指向a数组后面的内存单元,&a+1表示向后移16个存储单元
int *ptr2=(int *)((int)a+1);//表示a的存储单元的地址增加一个字节
printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其实指向的是a数组的最后一个单元,*ptr1则表示a数组的地址后移一个字节之后的4个连续存储单元所存储的值
return 0;
}
このコードの意味を解析してみましょう:
ptr1:&a + 1の値を強制的にint 型に変換し、それをint 型の変数ptrに割り当てます。ptr1は、配列aの次のint型データを指す必要があります。ptr1 [-1]は*(ptr1-1)として解析されます。つまり、ptr1は4バイト戻ります。したがって、その値は0x4です。
ptr2:上記の説明によれば、(int)a + 1の値は、要素a [0]の2番目のバイトのアドレスです。次に、このアドレスをint 型の値に強制し、ptr2に割り当てます。つまり、ptr2の値は、要素a [0]の2番目のバイトから始まる連続する4バイトのコンテンツでなければなりません。
詳細な分析を下の図に示します。
では、これらの4つの連続したバイトに正確に何が格納されているのでしょうか 言い換えると、要素a [0]とa [1]の値はどのように保存されますか?
これには、システムの大規模エンディアンモードと小規模エンディアンモードが含まれるため、ここではその影響について詳しく説明しません。現在のシステムのモードがわからないため、テストする方法を見つける必要があります。
次の関数を使用して、現在のシステムモードをテストできます。
int checkSystem()
{
union check
{
int i;
char ch;
} c;
c.i = 1;
return (c.ch ==1);//如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。
}
現在のシステムがビッグエンディアンモードの場合、この関数は0を返します。
リトルエンディアンモードの場合、関数は1を返します。
つまり、この関数の戻り値が1の場合、* ptr2の値は0x2000000です。この関数の戻り値が0の場合、* ptr2の値は0x100です。