【发布时间】:2014-10-03 10:14:02
【问题描述】:
这段代码 sn-p 摘自一本 linux 书籍。 如果这不适合在此处发布代码 sn-p,请告诉我。 我会删除它。谢谢。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buf[30];
char *p;
int i;
unsigned int index = 0;
//unsigned long index = 0;
printf("index-1 = %lx (sizeof %d)\n", index-1, sizeof(index-1));
for(i = 'A'; i <= 'Z'; i++)
buf[i - 'A'] = i;
p = &buf[1];
printf("%c: buf=%p p=%p p[-1]=%p\n", p[index-1], buf, p, &p[index-1]);
return 0;
}
在 32 位操作系统环境中: 无论索引的数据类型是 unsigned int 还是 unsigned long,此程序都能正常工作。
在 64 位操作系统环境中: 如果 index 声明为 unsigned int,同一程序将运行到“核心转储”。 但是,如果我只将索引的数据类型从 unsigned int 更改为 a) unsigned long 或 b) unsigned short, 这个程序也很好用。
书上的原因只告诉我64位会由于非负数而导致核心转储。但我不知道 unsigned long 和 unsigned short 工作但 unsigned int 的原因。
我很困惑的是
p + (0u -1) == p + UINT_MAX 当索引为无符号整数时。
但是,
p + (0ul - 1) == p[-1] 当索引为无符号长时。
我卡在这里了。
如果有人能帮忙详细说明一下,不胜感激!
谢谢。
这是我的 32 位的一些结果(RHEL5.10/gcc 版本 4.1.2 20080704)
和64位机(RHEL6.3/gcc版本4.4.6 20120305)
我不确定 gcc 版本在这里是否有什么不同。 所以,我也粘贴了信息。
在 32 位上:
我尝试了两个更改:
1) 将unsigned int index = 0修改为unsigned short index = 0。
2) 将unsigned int index = 0修改为unsigned char index = 0。
程序可以正常运行。
index-1 = ffffffff (sizeof 4)
A: buf=0xbfbdd5da p=0xbfbdd5db p[-1]=0xbfbdd5da
好像索引的数据类型会因为-1而提升为4字节。
在 64 位上:
我尝试了三个更改:
1) 将unsigned int index = 0修改为unsigned char index = 0。
It works!
index-1 = ffffffff (sizeof 4)
A: buf=0x7fffef304ae0 p=0x7fffef304ae1 p[-1]=0x7fffef304ae0
2) 将unsigned int index = 0修改为unsigned short index = 0。
It works!
index-1 = ffffffff (sizeof 4)
A: buf=0x7fff48233170 p=0x7fff48233171 p[-1]=0x7fff48233170
3) 将unsigned int index = 0修改为unsigned long index = 0。
It works!
index-1 = ffffffff (sizeof 8)
A: buf=0x7fffb81d6c20 p=0x7fffb81d6c21 p[-1]=0x7fffb81d6c20
但是,只有
unsigned int index = 0 在最后一个 printf 处运行到核心转储中。
index-1 = ffffffff (sizeof 4)
Segmentation fault (core dumped)
【问题讨论】:
-
您的第一个 printf 可能是问题所在。根据月相的结构和相位,printf 期望
%l值作为两个参数位置传递。 -
一般来说,您尝试访问的内存可能超出了您的可访问内存范围 -
p[index-1]等于从p + UINT_MAX位置读取。 -
感谢您的 cmets,Hot Licks。 1) 我将 %lx 更改为 %d,它运行到核心转储中。 2)我注释掉整行,只留下最后一个 printf,我仍然遇到核心转储。如果你想给我一些启示,想向你学习吗?谢谢。结果:在 32 位上:index-1 = ffffffff (sizeof 4) A:buf=0xbf8297b6 p=0xbf8297b7 p[-1]=0xbf8297b6 在 64 位上:分段错误(核心转储)
-
谢谢,冰袋。但是通过将数据类型从 unsigned int 切换为 unsigned long 可以毫无问题地通过。据我了解,p 指向 buf 的第二个元素,即 buf[1]。因此,p[index-1] 访问 buf 的第一个元素应该没有问题。但是,我对数组索引,无符号整数和-1之间的数据转换不是很清楚,因为我认为这可能是导致问题的原因......
-
使用
%d打印sizeof的结果是未定义的行为。使用%zu格式化size_t类型的对象。
标签: c linux 32bit-64bit