2个指针的区别是ptrdiff_t类型,<stddef.h>中定义的有符号整数类型。此类型的 printf 长度修饰符是 t。 2个指针的差值可以直接打印:
printf("pointer difference: %td\n", ptr - A[42]);
子数组维度(sizeof(A[0]) / sizeof(A[0][0]))的大小是size_t,无符号类型f是<stddef.h>中定义的sizeof运算符的结果。
此类型的 printf 长度修饰符是 z。可以直接打印对象的大小:
printf("array size in bytes: %zu\n", sizeof(A));
C 标准要求ptrdiff_t 至少能够表示-65535 和65535 之间的值,而size_t 必须具有至少0 到65535 的范围。
问题是:ptrdiff_t 被size_t 划分的类型是什么?
类型是通过应用6.3.1.8 通常的算术转换中指定的算术转换来确定的:
否则(如果两个操作数都具有整数类型),则对两个操作数执行整数提升。然后将以下规则应用于提升的操作数:
如果两个操作数的类型相同,则无需进一步转换。
否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则具有较小整数转换等级的类型的操作数将转换为具有较高等级的操作数的类型。
否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型输入。
否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数的所有值,则将无符号整数类型的操作数转换为操作数的类型带符号整数类型。
否则,两个操作数都转换为无符号整数类型,对应带符号整数类型的操作数类型。
根据ptrdiff_t 和size_t 使用的实际类型,结果的类型可能不同:
整数提升这样工作:如果类型int可以表示其类型的所有值,则将其转换为int,如果unsigned可以,则将其转换为unsigned ,否则类型不变。
因此,如果size_t 小于int,则size_t 被提升为有符号类型int,并且除法作为有符号除法执行,两个操作数首先转换为较大的@ 类型987654351@ 和 ptrdiff_t(在这种情况下也很可能是 int)。
如果size_t 是unsigned int 类型且ptrdiff_t 是int 类型,则ptrdiff_t 将转换为unsigned int,并且除法将作为结果类型为unsigned int 的无符号除法执行。
相反,如果size_t 为unsigned int 且ptrdiff_t 为long int 类型,则size_t 操作数将转换为long int 类型,则除法为有符号除法,结果类型为@987654367 @。
如果size_t 是unsigned long int 并且ptrdiff_t 是long int 类型(Linux 和OS/X 64 位),则ptrdiff_t 将转换为unsigned long int,并且除法是无符号除法,结果为输入unsigned long int。
如果size_t 是unsigned long long int 并且ptrdiff_t 是long long int 类型(Windows 64 位),则ptrdiff_t 将转换为unsigned long long int,并且除法是无符号除法,结果类型为unsigned long long int .
更多奇特的架构可能对size_t 和ptrdiff_t 类型有其他组合,从而为生成的类型带来更多可能性,例如long long int。
因此,行计算的类型是实现定义的:它可以是有符号的或无符号的,并且不同于size_t 和ptrdiff_t。
有多种方法可以为 printf 语句生成一致的类型和格式:
使用演员表:
printf("row number is %d\n", (int)((ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0]))));
使用中间变量:
int row = (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
printf("row number is %d\n", row);
使用额外的操作来强制更大的类型(不完美,因为size_t 可能大于unsigned long long):
printf("row number is %llu\n", 0ULL + (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
请注意,不能使用printf 格式%zu 用于size_t 和%td 用于ptrdiff_t,因为表达式的类型不一定是size_t 而不是ptrdiff_t。更糟糕的是,对于 Windows 用户来说,这些标准长度说明符不受 Microsoft C 运行时库的支持。正如 Jean-François Fabre 所建议的,对于使用 gcc 编译 C 代码并生成本机 Windows 应用程序的 MingW 用户,有一个解决方法:在命令行上指定 -D__USE_MINGW_ANSI_STDIO 告诉 gcc 使用自己的 @ 版本987654402@ 而不是 Microsoft 运行时的那个。
最后说明:如果ptr 不指向数组的第一行内,则表达式ptr - A[0] 实际上会调用未定义的行为,如6.5.6 加法运算符中所述:
- 当两个指针相减时,都应指向同一个数组对象的元素,或者指向数组对象最后一个元素的元素;结果是两个数组元素的下标之差。