关于cast的指针算法
我目前就读于CS107课程,该课程做出以下假设:关于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]指出了这一点,我同意 |....|....|....|....|....|
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