std :: ptrdiff_t和std :: size_t的奇怪typedef

时间:2018-02-04 09:04:31

标签: c++

类型std::size_t是一个无符号类型,可以存储任何类型的理论上可能的对象的最大大小,而std::ptrdiff_t是一个可以保存两个指针差异的有符号类型(这是另一种说法,它应该是C ++中数组索引的标准整数)。 C ++标准库决定使用std::size_t进行数组索引,但经常声明std::ptrdiff_t是更好的选择。哪一个是最好的是一个长期的辩论,我不想进入这里,但我一直认为第二个是第一个的未签名版本。在macOS上运行该程序给出

#include <cstddef>
#include <cstdio>

void f(int n) { std::printf("int"); };
void f(long n) { std::printf("long"); };
void f(long long n) { std::printf("long long"); };
void f(unsigned int n) { std::printf("unsigned int"); };
void f(unsigned long n) { std::printf("unsigned long"); };
void f(unsigned long long n) { std::printf("unsigned long long"); };

int main() {
  const std::ptrdiff_t n_ptrdiff = 0;
  const std::size_t n_size = 0;

  std::printf("std::ptrdiff_t is an alias for ");
  f(n_ptrdiff);
  std::printf("\n");

  std::printf("std::size_t is an alias for ");
  f(n_size);
  std::printf("\n");

  return 0;
}

在64位平台上,但编译为32位:

clang++ -m32 -std=c++11 type.cpp -o type-32-clang

给我以下结果:

std::ptrdiff_t is an alias for int
std::size_t is an alias for unsigned long

在这种情况下,std::size_t不是std::ptrdiff_t的无符号版本,即使它们具有相同的存储大小(4个字节)。虽然它符合标准,但对我来说似乎很奇怪。

有谁知道这个选择的理由?

1 个答案:

答案 0 :(得分:8)

TL; DR:为了与其他系统兼容,这样做是为了与其他系统兼容,等等。

clang通常会为signed longunsigned long提供ptrdiff_tsize_t,但commit "fix some differences between apple gcc and clang on darwin/x86-32"已将ptrdiff_t更改为{{} 1}}与gcc兼容。你不能让clang和gcc使用相同的C ++库,如果他们不同意这些基本的typedef。

gcc对signed int使用unsigned longsize_t使用signed int,因为这是Apple提供的内容:commit "Add Darwin (Mac OS X kernel) native support."显示在ptrdiff_t中:

gcc/config/darwin.h

没有提到具体原因,但此文件并非特定于任何处理器类型,它适用于所有Darwin系统,并且提交也触及/* Target definitions for Darwin (Mac OS X) systems. Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001 Free Software Foundation, Inc. Contributed by Apple Computer Inc. [...] /* The string value for __SIZE_TYPE__. */ #ifndef SIZE_TYPE #define SIZE_TYPE "long unsigned int" #endif /* Type used for ptrdiff_t, as a string used in a declaration. */ #undef PTRDIFF_TYPE #define PTRDIFF_TYPE "int" ,因此可能与兼容,将其带回1995年commit "Add preliminary V.4 and eABI support."

gcc/config/rs6000/rs6000.h

由于这不会重新定义/* Type used for ptrdiff_t, as a string used in a declaration. */ #undef PTRDIFF_TYPE #define PTRDIFF_TYPE "int" ,因此保留默认值SIZE_TYPE

gcc不是此平台的系统编译器,因此 反过来可能与IBM的编译器兼容。这似乎得到了gcc/config/rs6000/aix43.h

的支持
"unsigned long"

由于AIX的历史不公开,因此可能不会发生这种情况。