关于演员的指针算术

时间:2015-02-17 17:29:35

标签: c casting pointer-arithmetic

我目前正在参加CS107课程,该课程做出以下假设:

  • sizeof(int) == 4
  • sizeof(short) == 2
  • sizeof(char) == 1
  • big endianness

我的教授展示了以下代码:

int arr[5];
((short*)(((char*) (&arr[1])) + 8))[3] = 100;

以下是代表arr的20个字节:

|....|....|....|....|....|

我的教授说&arr[1]点在这里,我同意。

|....|....|....|....|....|
     x

我现在明白(char*)使指针成为char的宽度(1个字节)而不是int的宽度(4个字节)。

我不明白的是+ 8,我的教授在此指出:

|....|....|....|....|....|
                         x

但是它不应该指向这里,因为它的前进是char(1字节)的8倍?

|....|....|....|....|....|
               x

3 个答案:

答案 0 :(得分:4)

让我们一步一步来。您的表达式可以像这样分解:

((short*)(((char*) (&arr[1])) + 8))[3]
-----------------------------------------------------
char *base = (char *) &arr[1];
char *base_plus_offset = base + 8;
short *cast_into_short = (short *) base_plus_offset;
cast_into_short[3] = 100;

base_plus_offset指向数组中的字节位置12cast_into_short[3]指的是位置short的{​​{1}}值,在您的情况下为12 + sizeof(short) * 3

答案 1 :(得分:1)

这里有一些代码可以显示系统中修改了哪个字节,以及发生了什么的细分:

#include <stdio.h>

int main( int argc, char* argv[] )
{
    int arr[5];
    int i;

    for( i = 0; i < 5; i++ )
        arr[i] = 0;

    printf( "Before: " );

    for( i = 0; i < sizeof(int)*5; i++ )
        printf( "%2.2X ", ((char*)arr)[i] );

    printf( "\n" );

    ((short*)(((char*) (&arr[1])) + 8))[3] = 100;

    printf( "After: " );

    for( i = 0; i < sizeof(int)*5; i++ )
        printf( "%2.2X ", ((char*)arr)[i] );
    printf( "\n" );

    return 0;
}

从内心开始:

指向(arr + 4)的指针

&arr[1]
|...|...|...|...|...
    Xxxx

char指向(arr + 4)

(char*)(&arr[1])
|...|...|...|...|...
    X

char指针指向(arr + 4 + 8)

((char*)(&arr[1])) + 8)
|...|...|...|...|...
            X

指向(arr + 4 + 8)的短指针

(short*)((char*)(&arr[1])) + 8)
|...|...|...|...|...
            Xx

短于(arr + 4 + 8 +(3 * 2))(这是一个数组索引)

((short*)((char*)(&arr[1])) + 8))[3]
|...|...|...|...|...
                  Xx

这里修改的字节究竟取决于系统的字节顺序。在我的小端x86上,我得到以下输出:

Before: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
After:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 00

祝你好运。

答案 2 :(得分:1)

表达式将arr开始后的18个字节的两个字节设置为值100。

#include <stdio.h>

int main() {

    int arr[5];

    char* start=(char*)&arr;
    char* end=(char*)&((short*)(((char*) (&arr[1])) + 8))[3];

    printf("sizeof(int)=%zu\n",sizeof(int));
    printf("sizeof(short)=%zu\n",sizeof(short));
    printf("offset=%td <- THIS IS THE ANSWER\n",(end-start));
    printf("100=%04x (hex)\n",100);

    for(size_t i=0;i<5;++i){

       printf("arr[%zu]=%d (%08x hex)\n",i,arr[i],arr[i]);

    }

}

可能的输出:

sizeof(int)=4
sizeof(short)=2
offset=18 <- THIS IS THE ANSWER
100=0064 (hex)
arr[0]=0 (00000000 hex)
arr[1]=0 (00000000 hex)
arr[2]=0 (00000000 hex)
arr[3]=0 (00000000 hex)
arr[4]=6553600 (00640000 hex)

在你所有教授的诡计中,他转移了1个整数,8个字符/字节和3个短裤,4 + 8 + 6 = 18个字节。宾果

注意这个输出显示我运行它的机器有4个字节的整数,2个字节短(普通)和小端,因为数组的最后两个字节分别设置为0x64和0x00。

我发现你的图表令人困惑,因为如果你的意思是&#39; |&#39;它并不是很清楚。是否是地址。

|....|....|....|....|
012345678901234567890
    ^     1 ^     ^ 2
A   X       C     S B

包括条形码(&#39; |&#39;)A是Arr的开头,B是结束后的一个&#39; (C中的法律概念)。

X是表达式&amp; Arr [1]引用的地址。 C由表达式(((char *)(&amp; arr [1]))+ 8)组成。 S由整个表达。 S和后面的字节被分配,这意味着什么取决于您的平台的字节序。

我把它留作练习来确定输出的类似但是大端平台的输出。任何人? 我从评论中注意到你是big-endian和我的小端(停止窃笑)。 您只需要更改输出的一行。