gpt4 book ai didi

c++ - (ptr - A[0])/(sizeof(A[0])/sizeof(A[0][0])) 的类型是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:27:14 25 4
gpt4 key购买 nike

我有一个二维数组 A 和一个指向其中某处的指针 ptr 。我知道如何计算行号,但表达式的实际类型似乎不可移植:

#include <stdio.h>

int main(void) {
int A[100][100];
int *ptr = &A[42][24];

printf("row number is %d\n", (ptr - A[0]) / (sizeof(A[0]) / sizeof(A[0][0])));
printf("col number is %d\n", (ptr - A[0]) % (sizeof(A[0]) / sizeof(A[0][0])));
return 0;
}

在 OS/X 上, clang 编译器这样提示:
warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]

在 Linux 上, gcc 给出了类似的警告,但在 Windows 上,我得到了不同的诊断:
warning: format specifies type 'int' but the argument has type 'unsigned long long' [-Wformat]

这个表达式的实际类型是什么?

有没有办法将表达式传递给 printf 而没有丑陋的 Actor 阵容?

最佳答案

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 是 sizeof 中定义的 <stddef.h> 运算符的结果。

此类型的 printf 长度修饰符是 z 。对象的大小可以直接打印:
printf("array size in bytes: %zu\n", sizeof(A));

C 标准要求 ptrdiff_t 至少能够表示 -6553565535 之间的值,而 size_t 必须具有至少 065535 的范围。

问题是: ptrdiff_t 除以 size_t 的类型是什么?

该类型通过应用 6.3.1.8 中指定的算术转换来确定,通常算术转换 :

Otherwise (if both operands have integer types), the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

  • If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

  • Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

  • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.



根据用于 ptrdiff_tsize_t 的实际类型,结果的类型可能不同:

整数提升是这样工作的:如果类型 int 可以表示其类型的所有值,则将其转换为 int ,如果 unsigned 可以,则转换为 unsigned ,否则类型不变。

因此,如果 size_t 小于 intsize_t 被提升为 int ,一种有符号类型,并且除法作为有符号除法执行,两个操作数首先转换为更大类型的 intptrdiff_t (很可能也是 int 在这个案例)。

如果 size_t 的类型为 unsigned intptrdiff_t 的类型为 int ,则 ptrdiff_t 将转换为 unsigned int 并且除法作为结果类型为 unsigned int 的无符号除法执行。

相反,如果 size_tunsigned int 并且 ptrdiff_t 是类型 long int ,那么 size_t 操作数被转换为类型 long int ,除法是有符号除法,结果类型是 long int

如果 size_tunsigned long int 并且 ptrdiff_tlong int 类型(Linux 和 OS/X 64 位),则 ptrdiff_t 将转换为 unsigned long int 并且除法是具有结果类型 unsigned long int 的无符号除法。

如果 size_tunsigned long long intptrdiff_tlong long int 类型(Windows 64 位),则 ptrdiff_t 将转换为 unsigned long long int 并且除法是具有结果类型 unsigned long long int 的无符号除法。

更奇特的架构可能有 size_tptrdiff_t 类型的其他组合,从而为结果类型带来更多可能性,例如 long long int

因此,行计算的类型是实现定义的:它可以是有符号或无符号的,并且不同于 size_tptrdiff_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 代码并生成 native Windows 应用程序的 MingW 用户,有一种解决方法:在命令行上指定 -D__USE_MINGW_ANSI_STDIO 告诉 gcc 使用自己的 printf 版本而不是 Microsoft 的版本运行。

最后一点:如果 ptr - A[0] 不指向数组的第一行,则表达式 ptr 实际上会调用未定义的行为,如 6.5.6 Additive operators 中所述:

  1. When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.

关于c++ - (ptr - A[0])/(sizeof(A[0])/sizeof(A[0][0])) 的类型是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40329101/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com