我目前正在参加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
但是它不应该指向这里,因为它的前进是char(1字节)的8倍?
|....|....|....|....|....|
x
答案 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
指向数组中的字节位置12
。 cast_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和我的小端(停止窃笑)。 您只需要更改输出的一行。