c - Unsigned int 从 32 位到 64 位操作系统

标签 c linux 32bit-64bit

此代码片段摘自一本 linux 书籍。 如果不适合在此处发布代码片段,请告诉我。 我会删除它。谢谢。

#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位会因为非负数导致core-dump。但是我不知道为什么 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=0x7ffff304ae0 p=0x7ffff304ae1 p[-1]=0x7ffff304ae0

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)

段错误(核心转储)

最佳答案

不要欺骗编译器!

printf 传递一个 int 它需要一个 long (%ld) 是未定义的行为。
(创建一个指向任何有效对象外部(而不仅仅是在一个对象后面)的指针也是 UB ......)

更正格式说明符和指针算法(包括作为特殊情况的索引),一切都会正常工作。

UB 包括“它按预期工作”以及“灾难性故障”。

顺便说一句:如果您礼貌地向编译器询问所有警告,它会警告您。使用 -Wall -Wextra -pedantic 或类似的。

关于c - Unsigned int 从 32 位到 64 位操作系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25228791/

相关文章:

linux - 如何在循环中使用awk读取每十行文件?

linux - 文件或目录更改时如何运行 shell 脚本?

python - 用于 32 位和 64 位并行的 Anaconda 环境?

objective-c - 什么时候转换到 `int` 会导致问题?

c - 整数常量的无效后缀 "b020000.usdhc"

c - 从C中的文件中读取特定字段

linux - 在期望脚本中终止 screen session

c++ - 找到质数?

c - 程序要求用户输入文本文件,然后用相同长度的单词替换单词

windows - 会有 Win64 API 吗?