关于cast的指针算法

关于cast的指针算法,c,casting,pointer-arithmetic,C,Casting,Pointer Arithmetic,我目前就读于CS107课程,该课程做出以下假设: sizeof(int)==4 sizeof(short)==2 sizeof(char)==1 大端性 我的教授展示了以下代码: int arr[5]; ((short*)(((char*) (&arr[1])) + 8))[3] = 100; 以下是表示arr的20个字节: |....|....|....|....|....| 我的教授指出,&arr[1]指出了这一点,我同意 |....|....|....|....|....|

我目前就读于CS107课程,该课程做出以下假设:

  • sizeof(int)==4
  • sizeof(short)==2
  • sizeof(char)==1
  • 大端性
我的教授展示了以下代码:

int arr[5];
((short*)(((char*) (&arr[1])) + 8))[3] = 100;
以下是表示arr的20个字节:

|....|....|....|....|....|
我的教授指出,
&arr[1]
指出了这一点,我同意

|....|....|....|....|....|
     x
我现在明白了
(char*)
使指针的宽度为char(1字节),而不是int(4字节)

我不明白的是
+8
,我的教授在这里说:

|....|....|....|....|....|
                         x
但是它不应该指向这里吗,因为它是字符大小的8倍(1字节)


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

((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\u plus\u offset
指向数组中字节位置
12
cast\u into\u short[3]
指位于
12+sizeof(short)*3
位置的
short
值,在您的情况下,它是
18

以下是一些代码,可以显示您的系统中哪个字节被修改,以及发生的情况:

#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+4+8)的字符指针

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

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

具体修改哪个字节取决于系统的endianess。在我的little endian 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

祝您好运。

表达式将
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]);

    }

}
包括条形(“|”)A是
Arr
的开始,B是“结束后的一个”(C中的一个法律概念)

X是表达式&Arr[1]引用的地址。 C通过表达式(((char*)(&arr[1]))+8)。 这是一个完整的表达。 S和下面的字节被分配给,这意味着什么取决于平台的endian属性

我把它留作一个练习,以确定类似但大端平台上的输出是谁输出的。任何人 我从评论中注意到你是big endian,我是little endian(别笑了)。
您只需要更改一行输出。

您是对的。写一些代码来打印指针的值,以向教授表明你是对的。这完全取决于
sizeof(int)
,这不一定是
4
@BlagovestBuyukliev我的教授假设
sizeof(int)
在上课期间是4。抱歉,我应该提到这一点。Alexey-1,教授-0。有些关联:这是严格别名冲突的经典示例,因此此代码没有任何定义良好的语义。您对表达式的分析是正确的,但您似乎误解了OP的说法,因为您说他是不对的。他的(迄今为止的一次)编辑没有任何区别,因为添加到
short*
的cast不是他要查询的子表达式的一部分。@JohnBollinger谢谢,我已经更正了这个说法!还要加上指针位置和内存使用,这就是为什么这样的代码不应该写在一行上。这里发生的事情一目了然。在问题的代码中,我假设教授用太多的括号把自己弄糊涂了。@gnasher729:或者至少避免像
(char*)(&arr[1])这样完全无用的括号。
(这似乎是为那些不知道cast可以采用一元表达式的人准备的,如果不允许的话,没有parens就不会编译什么;这个“澄清”的疑问甚至不能用优先级来表达)。虽然我同意在这种情况下它可能应该被拆分。@mafso:第二对括号也没用,所以该表达式的非cargo cult版本应该是:
((short*)((char*)&arr[1]+8))[3]
(char*)(&arr[1])
|...|...|...|...|...
    X
((char*)(&arr[1])) + 8)
|...|...|...|...|...
            X
(short*)((char*)(&arr[1])) + 8)
|...|...|...|...|...
            Xx
((short*)((char*)(&arr[1])) + 8))[3]
|...|...|...|...|...
                  Xx
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
#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)
|....|....|....|....|
012345678901234567890
    ^     1 ^     ^ 2
A   X       C     S B