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

Ins*_*oop 3 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;
}
Run Code Online (Sandbox Code Playgroud)

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

clang++ -m32 -std=c++11 type.cpp -o type-32-clang
Run Code Online (Sandbox Code Playgroud)

给我以下结果:

std::ptrdiff_t is an alias for int
std::size_t is an alias for unsigned long
Run Code Online (Sandbox Code Playgroud)

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

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

小智 8

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


铛通常不得不signed longunsigned long用于ptrdiff_tsize_t您预期的那样,但承诺"固定在苹果达尔文gcc和铛之间存在一些差异/ X86-32"ptrdiff_tsigned int了与海湾合作委员会的兼容性.你不能让clang和gcc使用相同的C++库,如果他们不同意这些基本的typedef.

GCC使用unsigned longsize_t,但signed int对于ptrdiff_t因为这是苹果贡献:提交"添加达尔文(Mac OS X的内核)的原生支持." 显示在gcc/config/darwin.h:

/* 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" 
Run Code Online (Sandbox Code Playgroud)

无特殊原因被提及,但这个文件不是针对任何处理器类型,它适用于所有Darwin系统,并提交也触动gcc/config/rs6000/rs6000.h,使其成为可能,这是与兼容,把它回到1995年提交的"添加初步的V.4和eABI支持." :

/* Type used for ptrdiff_t, as a string used in a declaration.  */
#undef  PTRDIFF_TYPE
#define PTRDIFF_TYPE "int"
Run Code Online (Sandbox Code Playgroud)

由于这不会重新定义SIZE_TYPE,因此保留默认值"unsigned long".

GCC不是系统的编译器这个平台,所以反过来很可能与IBM的编译器的兼容性.这似乎得到以下支持gcc/config/rs6000/aix43.h:

/* AIX 4.3 typedefs ptrdiff_t as "long" while earlier releases used "int".  */

#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE "long int"
Run Code Online (Sandbox Code Playgroud)

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