将 sizeof() 的结果分配给 ssize_t
Assign result of sizeof() to ssize_t
我碰巧需要将 sizeof(x)
的结果与 ssize_t
的结果进行比较。
当然 GCC 报错了(幸运的是我(我用的是 -Wall -Wextra -Werror
)),我决定做一个宏来得到 sizeof()
.
的签名版本
#define ssizeof (ssize_t)sizeof
然后我可以这样使用它:
for (ssize_t i = 0; i < ssizeof(x); i++)
问题是,我能保证SSIZE_MAX >= SIZE_MAX
吗?我想,可悲的是,这永远不会是真的。
或者至少 sizeof(ssize_t) == sizeof(size_t)
,这将减少一半的值,但仍然足够接近。
我在 POSIX 文档中没有找到 ssize_t
和 size_t
之间的任何关系。
相关问题:
请注意,您实际上不能这样做。
x86 中可能的最大对象 Linux 大小刚好低于 0xB0000000,而 SSIZE_T_MAX
是 0x7FFFFFFF。
我还没有检查 read
和东西是否真的可以处理最大可能的对象,但如果它们可以的话,它会像这样工作:
ssize_t result = read(fd, buf, count);
if (result != -1) {
size_t offset = (size_t) result;
/* handle success */
} else {
/* handle failure */
}
您可能会发现 libc
被破坏了。如果是这样,如果内核是好的,这将起作用:
ssize_t result = sys_read(fd, buf, count);
if (result >= 0 || result < -256) {
size_t offset = (size_t) result;
/* handle success */
} else {
errno = (int)-result;
/* handle failure */
}
不保证SSIZE_MAX >= SIZE_MAX
。事实上,情况不太可能是这样,因为 size_t
和 ssize_t
很可能是对应的无符号和有符号类型,所以(在所有实际架构上)SIZE_MAX > SSIZE_MAX
。将无符号值转换为无法保存该值的有符号类型是未定义的行为。所以从技术上讲,您的宏有问题。
实际上,至少在 64 位平台上,如果要转换为 ssize_t
的值是实际存在的对象的大小,则不太可能遇到麻烦。但如果对象是理论上的(例如 sizeof(char[3][1ULL<<62])
),您可能会感到不愉快。
注意类型ssize_t
唯一有效的负值是-1,这是一个错误指示。您可能会混淆由 Posix 定义的 ssize_t
和自 C99 以来在标准 C 中定义的 ptrdiff_t
。这两种类型在大多数平台上是相同的,通常是 size_t
对应的有符号整数类型,但其中 none 的行为由任一标准保证。但是,这两种类型的语义是不同的,使用时需要注意:
ssize_t
由多个 Posix 接口 return 编辑,以允许函数发出已处理字节数或错误指示的信号;错误指示必须为 -1。没有期望任何可能的尺寸都适合 ssize_t
; Posix 理由指出:
A conforming application would be constrained not to perform I/O in pieces larger than {SSIZE_MAX}
.
对于returnssize_t
的大部分接口来说这不是问题,因为Posix一般不需要接口来保证处理所有数据。例如,read
和 write
都接受描述缓冲区长度的 size_t
read/written 和 return 描述缓冲区长度的 ssize_t
实际字节数 read/written;这意味着即使有更多数据可用,也不会超过 SSIZE_MAX
字节 read/written 。然而,Posix 的基本原理还指出,一个特定的实现可能会提供一个扩展,允许处理更大的块("a conforming application using extensions would be able to use the full range if the implementation provided an extended range"),这个想法是该实现可以,例如,指定 return 除了 -1 之外的值将通过将它们转换为 size_t
来解释。这样的扩展是不可移植的;在实践中,大多数实现确实将可以在单个调用中处理的字节数限制为可以在 ssize_t
.
中报告的数字
ptrdiff_t
是(在标准 C 中)两个指针之间的差异结果的类型。为了明确定义减法指针,两个指针必须指向同一个对象,要么指向对象,要么指向紧跟在对象之后的字节。 C 委员会认识到,如果 ptrdiff_t
是 size_t
的带符号等价物,那么两个指针之间的差异可能无法表示,从而导致未定义的行为,但他们更喜欢要求 ptrdiff_t
是比 size_t
更大的类型。你可以反对这个决定——很多人都反对——但它自 C90 以来就已经存在,现在似乎不太可能改变。 (来自 §6.5.6/9 的当前标准措辞:"If the result is not representable in an object of that type [ptrdiff_t
], the behavior is undefined.")
与 Posix 一样,C 标准没有定义未定义的行为,因此将其解释为 禁止 两个指针相减是错误的大物体。始终允许实现定义标准未定义的行为结果,因此实现指定如果 P
和 Q
是指向同一对象的两个指针是完全有效的,其中 P >= Q
,那么即使减法溢出,(size_t)(P - Q)
也是指针之间数学上正确的差值。当然,依赖于此类扩展的代码不会完全可移植,但如果扩展足够普遍,那可能不是问题。
作为最后一点,使用 -1 作为错误指示(在 ssize_t
中)和作为指针减法的可能可转换结果(在 ptrdiff_t
中)的歧义不太可能如果 size_t
与指针一样大,则在实践中出现。如果 size_t
和指针一样大,那么 P-Q
在数学上正确的值可能是 (size_t)(-1)
(又名 SIZE_MAX
)的唯一方法是 P
和 Q
指的是大小 SIZE_MAX
,假设 size_t
与指针的宽度相同,这意味着对象加上后面的字节占据了所有可能的指针价值。这与某些指针值 (NULL
) 与任何有效地址不同的要求相矛盾,因此我们可以得出结论,对象的真实最大大小必须小于 SIZE_MAX
。
我要把它当作一个 X-Y 问题。您遇到的问题是您想要将有符号数与无符号数进行比较。而不是将 sizeof
的结果转换为 ssize_t
,您应该检查 ssize_t
值是否小于零。如果是,那么您知道它小于您的 size_t
值。如果不是,则可以将其转换为 size_t
,然后进行比较。
例如,这里有一个比较函数,如果有符号数小于无符号数,则为 returns -1
,如果等于则为 0,如果有符号数大于无符号数则为 1数量:
int compare(ssize_t signed_number, size_t unsigned_number) {
int ret;
if (signed_number < 0 || (size_t) signed_number < unsigned_number) {
ret = -1;
}
else {
ret = (size_t) signed_number > unsigned_number;
}
return ret;
}
如果您想要的只是等同于 <
的操作,您可以使用类似这样的操作来简化一些操作:
(signed_number < 0 || (size_t) signed_number < unsigned_number))
如果 signed_number
小于 unsigned_number
,该行会给你 1
并且它限制了分支开销。只需要一个额外的 <
操作和一个 logical-OR
.
ssize_t 是 POSIX 类型,它没有定义为 C 标准的一部分。 POSIX定义ssize_t必须能够处理区间[-1,SSIZE_MAX]内的数字,所以原则上它甚至不需要是普通的有符号类型。这个有点奇怪的定义的原因是唯一使用 ssize_t 的地方是 read/write/etc 的 return 值。函数。
实际上,它始终是与 size_t 大小相同的普通有符号类型。但是如果你想对你的类型真正迂腐,除了处理 IO 系统调用的 return 值之外,你不应该将它用于其他目的。对于一般的 "pointer-sized" 有符号整数类型,C89 定义了 ptrdiff_t。这在实践中将与 ssize_t.
相同
此外,如果您查看 official spec for read(),您会看到 'nbyte' 参数表示 'If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.'。因此,即使 size_t 能够表示比 SSIZE_MAX 更大的值,使用比 IO 系统调用更大的值是实现定义的行为(唯一使用 ssize_t 的地方,如前所述)。与 write() 等类似
我碰巧需要将 sizeof(x)
的结果与 ssize_t
的结果进行比较。
当然 GCC 报错了(幸运的是我(我用的是 -Wall -Wextra -Werror
)),我决定做一个宏来得到 sizeof()
.
#define ssizeof (ssize_t)sizeof
然后我可以这样使用它:
for (ssize_t i = 0; i < ssizeof(x); i++)
问题是,我能保证SSIZE_MAX >= SIZE_MAX
吗?我想,可悲的是,这永远不会是真的。
或者至少 sizeof(ssize_t) == sizeof(size_t)
,这将减少一半的值,但仍然足够接近。
我在 POSIX 文档中没有找到 ssize_t
和 size_t
之间的任何关系。
相关问题:
请注意,您实际上不能这样做。
x86 中可能的最大对象 Linux 大小刚好低于 0xB0000000,而 SSIZE_T_MAX
是 0x7FFFFFFF。
我还没有检查 read
和东西是否真的可以处理最大可能的对象,但如果它们可以的话,它会像这样工作:
ssize_t result = read(fd, buf, count);
if (result != -1) {
size_t offset = (size_t) result;
/* handle success */
} else {
/* handle failure */
}
您可能会发现 libc
被破坏了。如果是这样,如果内核是好的,这将起作用:
ssize_t result = sys_read(fd, buf, count);
if (result >= 0 || result < -256) {
size_t offset = (size_t) result;
/* handle success */
} else {
errno = (int)-result;
/* handle failure */
}
不保证SSIZE_MAX >= SIZE_MAX
。事实上,情况不太可能是这样,因为 size_t
和 ssize_t
很可能是对应的无符号和有符号类型,所以(在所有实际架构上)SIZE_MAX > SSIZE_MAX
。将无符号值转换为无法保存该值的有符号类型是未定义的行为。所以从技术上讲,您的宏有问题。
实际上,至少在 64 位平台上,如果要转换为 ssize_t
的值是实际存在的对象的大小,则不太可能遇到麻烦。但如果对象是理论上的(例如 sizeof(char[3][1ULL<<62])
),您可能会感到不愉快。
注意类型ssize_t
唯一有效的负值是-1,这是一个错误指示。您可能会混淆由 Posix 定义的 ssize_t
和自 C99 以来在标准 C 中定义的 ptrdiff_t
。这两种类型在大多数平台上是相同的,通常是 size_t
对应的有符号整数类型,但其中 none 的行为由任一标准保证。但是,这两种类型的语义是不同的,使用时需要注意:
ssize_t
由多个 Posix 接口 return 编辑,以允许函数发出已处理字节数或错误指示的信号;错误指示必须为 -1。没有期望任何可能的尺寸都适合ssize_t
; Posix 理由指出:A conforming application would be constrained not to perform I/O in pieces larger than
{SSIZE_MAX}
.对于return
ssize_t
的大部分接口来说这不是问题,因为Posix一般不需要接口来保证处理所有数据。例如,read
和write
都接受描述缓冲区长度的size_t
read/written 和 return 描述缓冲区长度的ssize_t
实际字节数 read/written;这意味着即使有更多数据可用,也不会超过SSIZE_MAX
字节 read/written 。然而,Posix 的基本原理还指出,一个特定的实现可能会提供一个扩展,允许处理更大的块("a conforming application using extensions would be able to use the full range if the implementation provided an extended range"),这个想法是该实现可以,例如,指定 return 除了 -1 之外的值将通过将它们转换为size_t
来解释。这样的扩展是不可移植的;在实践中,大多数实现确实将可以在单个调用中处理的字节数限制为可以在ssize_t
. 中报告的数字
ptrdiff_t
是(在标准 C 中)两个指针之间的差异结果的类型。为了明确定义减法指针,两个指针必须指向同一个对象,要么指向对象,要么指向紧跟在对象之后的字节。 C 委员会认识到,如果ptrdiff_t
是size_t
的带符号等价物,那么两个指针之间的差异可能无法表示,从而导致未定义的行为,但他们更喜欢要求ptrdiff_t
是比size_t
更大的类型。你可以反对这个决定——很多人都反对——但它自 C90 以来就已经存在,现在似乎不太可能改变。 (来自 §6.5.6/9 的当前标准措辞:"If the result is not representable in an object of that type [ptrdiff_t
], the behavior is undefined.")与 Posix 一样,C 标准没有定义未定义的行为,因此将其解释为 禁止 两个指针相减是错误的大物体。始终允许实现定义标准未定义的行为结果,因此实现指定如果
P
和Q
是指向同一对象的两个指针是完全有效的,其中P >= Q
,那么即使减法溢出,(size_t)(P - Q)
也是指针之间数学上正确的差值。当然,依赖于此类扩展的代码不会完全可移植,但如果扩展足够普遍,那可能不是问题。
作为最后一点,使用 -1 作为错误指示(在 ssize_t
中)和作为指针减法的可能可转换结果(在 ptrdiff_t
中)的歧义不太可能如果 size_t
与指针一样大,则在实践中出现。如果 size_t
和指针一样大,那么 P-Q
在数学上正确的值可能是 (size_t)(-1)
(又名 SIZE_MAX
)的唯一方法是 P
和 Q
指的是大小 SIZE_MAX
,假设 size_t
与指针的宽度相同,这意味着对象加上后面的字节占据了所有可能的指针价值。这与某些指针值 (NULL
) 与任何有效地址不同的要求相矛盾,因此我们可以得出结论,对象的真实最大大小必须小于 SIZE_MAX
。
我要把它当作一个 X-Y 问题。您遇到的问题是您想要将有符号数与无符号数进行比较。而不是将 sizeof
的结果转换为 ssize_t
,您应该检查 ssize_t
值是否小于零。如果是,那么您知道它小于您的 size_t
值。如果不是,则可以将其转换为 size_t
,然后进行比较。
例如,这里有一个比较函数,如果有符号数小于无符号数,则为 returns -1
,如果等于则为 0,如果有符号数大于无符号数则为 1数量:
int compare(ssize_t signed_number, size_t unsigned_number) {
int ret;
if (signed_number < 0 || (size_t) signed_number < unsigned_number) {
ret = -1;
}
else {
ret = (size_t) signed_number > unsigned_number;
}
return ret;
}
如果您想要的只是等同于 <
的操作,您可以使用类似这样的操作来简化一些操作:
(signed_number < 0 || (size_t) signed_number < unsigned_number))
如果 signed_number
小于 unsigned_number
,该行会给你 1
并且它限制了分支开销。只需要一个额外的 <
操作和一个 logical-OR
.
ssize_t 是 POSIX 类型,它没有定义为 C 标准的一部分。 POSIX定义ssize_t必须能够处理区间[-1,SSIZE_MAX]内的数字,所以原则上它甚至不需要是普通的有符号类型。这个有点奇怪的定义的原因是唯一使用 ssize_t 的地方是 read/write/etc 的 return 值。函数。
实际上,它始终是与 size_t 大小相同的普通有符号类型。但是如果你想对你的类型真正迂腐,除了处理 IO 系统调用的 return 值之外,你不应该将它用于其他目的。对于一般的 "pointer-sized" 有符号整数类型,C89 定义了 ptrdiff_t。这在实践中将与 ssize_t.
相同此外,如果您查看 official spec for read(),您会看到 'nbyte' 参数表示 'If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.'。因此,即使 size_t 能够表示比 SSIZE_MAX 更大的值,使用比 IO 系统调用更大的值是实现定义的行为(唯一使用 ssize_t 的地方,如前所述)。与 write() 等类似