将sizeof()的结果分配给ssize_t [英] Assign result of sizeof() to ssize_t

查看:88
本文介绍了将sizeof()的结果分配给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_tsize_t之间的任何关系.

相关问题:

应使用哪种类型循环遍历数组?

解决方案

不能保证SSIZE_MAX >= SIZE_MAX.实际上,情况不太可能,因为size_tssize_t可能是对应的无符号和有符号类型,因此(在所有实际体系结构上)SIZE_MAX > SSIZE_MAX.将无符号的值强制转换为无法保存该值的带符号的类型是未定义的行为.因此,从技术上讲,您的宏存在问题.

实际上,至少在64位平台上,如果要转换为ssize_t的值是实际存在的对象的大小,则不太可能遇到麻烦.但是,如果对象是理论性的(例如sizeof(char[3][1ULL<<62])),则可能会令人不快.

请注意,类型ssize_t的唯一有效负值是-1,这是一个错误指示.您可能会将Posix定义的ssize_t(自C99开始在标准C中定义)相混淆.这两种类型在大多数平台上都是相同的,并且通常是与size_t对应的有符号整数类型,但是任何一种标准都不能保证这些行为.但是,这两种类型的语义是不同的,因此在使用它们时应注意以下几点:

  • ssize_t由多个Posix接口返回,以使该函数可以发信号通知已处理的字节数或错误指示.错误指示必须为-1.没想到ssize_t可以容纳任何可能的大小; Posix的基本原理指出:

    符合条件的应用程序将被限制为不能以大于{SSIZE_MAX}的片段的形式执行I/O.

    对于大多数返回ssize_t的接口来说,这不是问题,因为Posix通常不需要接口来保证处理所有数据.例如,readwrite都接受描述要读取/写入的缓冲区长度的size_t,并返回描述实际读取/写入的字节数的ssize_t.这意味着即使有更多数据可用,也不会读取/写入不超过SSIZE_MAX个字节.但是,Posix原理还指出,特定的实现可能会提供一个扩展,该扩展允许处理更大的块(如果扩展提供了扩展范围,则使用扩展的兼容应用程序将能够使用整个范围"),该实现可以例如指定将-1以外的返回值转换为size_t来解释.这样的扩展将无法移植;在实践中,大多数实现确实将一次调用中可以处理的字节数限制为可以在ssize_t中报告的字节数.

  • ptrdiff_t是(在标准C中)两个指针之间的差值结果的类型.为了正确定义指针的减法,两个指针必须指向同一对象,方法是指向该对象或指向紧随该对象之后的字节. C委员会认识到,如果ptrdiff_tsize_t的有符号等效项,则可能无法表示两个指针之间的差异,从而导致不确定的行为,但他们宁愿要求ptrdiff_t为a类型大于size_t.您可以对这个决定提出异议-很多人已经做出了-但自C90以来它就一直存在,并且现在看来改变的可能性不大. (来自§ 6.5.6/9的当前标准措辞:如果结果无法在类型[ptrdiff_t]的对象中表示,则该行为是不确定的.")

    与Posix一样,C标准没有定义未定义的行为,因此将禁止解释为非常大的对象中的两个指针相减是错误的.始终允许实现定义标准未定义的行为结果,因此对于实现来说,指定PQ是指向同一对象的两个指针,而P >= Q则完全有效. (size_t)(P - Q)是指针之间在数学上正确的差,即使减法溢出也是如此.当然,依赖于这种扩展的代码不会完全可移植,但是如果扩展足够普遍,那可能就不成问题了.

最后,实际上,在实际情况中不太可能同时使用-1作为错误指示(在ssize_t中)和作为可能的指针减法结果(在ptrdiff_t中)使用模棱两可size_t和指针一样大.如果size_t与指针一样大,则P-Q的数学正确值可以是(size_t)(-1)(又名SIZE_MAX)的唯一方法是PQ所引用的对象是大小SIZE_MAX,假定size_t与指针的宽度相同,则表示对象加上下一个字节占据了每个可能的指针值.这与某些指针值(NULL)与任何有效地址不同的要求相矛盾,因此我们可以得出结论,对象的真实最大大小必须小于SIZE_MAX.

It happened to me that I needed to compare the result of sizeof(x) to a ssize_t.

Of course GCC gave an error (lucky me (I used -Wall -Wextra -Werror)), and I decided to do a macro to have a signed version of sizeof().

#define ssizeof (ssize_t)sizeof

And then I can use it like this:

for (ssize_t i = 0; i < ssizeof(x); i++)

The problem is, do I have any guarantees that SSIZE_MAX >= SIZE_MAX? I imagine that sadly this is never going to be true.

Or at least that sizeof(ssize_t) == sizeof(size_t), which would cut half of the values but would still be close enough.

I didn't find any relation between ssize_t and size_t in the POSIX documentation.

Related question:

What type should be used to loop through an array?

解决方案

There is no guarantee that SSIZE_MAX >= SIZE_MAX. In fact, it is very unlikely to be the case, since size_t and ssize_t are likely to be corresponding unsigned and signed types, so (on all actual architectures) SIZE_MAX > SSIZE_MAX. Casting an unsigned value to a signed type which cannot hold that value is Undefined Behaviour. So technically, your macro is problematic.

In practice, at least on 64-bit platforms, you're unlikely to get into trouble if the value you are converting to ssize_t is the size of an object which actually exists. But if the object is theoretical (eg sizeof(char[3][1ULL<<62])), you might get an unpleasant surprise.

Note that the only valid negative value of type ssize_t is -1, which is an error indication. You might be confusing ssize_t, which is defined by Posix, with ptrdiff_t, which is defined in standard C since C99. These two types are the same on most platforms, and are usually the signed integer type corresponding to size_t, but none of those behaviours is guaranteed by either standard. However, the semantics of the two types are different, and you should be aware of that when you use them:

  • ssize_t is returned by a number of Posix interfaces in order to allow the function to signal either a number of bytes processed or an error indication; the error indication must be -1. There is no expectation that any possible size will fit into ssize_t; the Posix rationale states that:

    A conforming application would be constrained not to perform I/O in pieces larger than {SSIZE_MAX}.

    This is not a problem for most of the interfaces which return ssize_t because Posix generally does not require interfaces to guarantee to process all data. For example, both read and write accept a size_t which describes the length of the buffer to be read/written and return an ssize_t which describes the number of bytes actually read/written; the implication is that no more than SSIZE_MAX bytes will be read/written even if more data were available. However, the Posix rationale also notes that a particular implementation may provide an extension which allows larger blocks to be processed ("a conforming application using extensions would be able to use the full range if the implementation provided an extended range"), the idea being that the implementation could, for example, specify that return values other than -1 were to be interpreted by casting them to size_t. Such an extension would not be portable; in practices, most implementations do limit the number of bytes which can be processed in a single call to the number which can be reported in ssize_t.

  • ptrdiff_t is (in standard C) the type of the result of the difference between two pointers. In order for subtraction of pointers to be well defined, the two pointers must refer to the same object, either by pointing into the object or by pointing at the byte immediately following the object. The C committee recognised that if ptrdiff_t is the signed equivalent of size_t, then it is possible that the difference between two pointers might not be representable, leading to undefined behaviour, but they preferred that to requiring that ptrdiff_t be a larger type than size_t. You can argue with this decision -- many people have -- but it has been in place since C90 and it seems unlikely that it will change now. (Current standard wording from , §6.5.6/9: "If the result is not representable in an object of that type [ptrdiff_t], the behavior is undefined.")

    As with Posix, the C standard does not define undefined behaviour, so it would be a mistake to interpret that as forbidding the subtraction of two pointers in very large objects. An implementation is always allowed to define the result of behaviour left undefined by the standard, so that it is completely valid for an implementation to specify that if P and Q are two pointers to the same object where P >= Q, then (size_t)(P - Q) is the mathematically correct difference between the pointers even if the subtraction overflows. Of course, code which depends on such an extension won't be fully portable, but if the extension is sufficiently common that might not be a problem.

As a final point, the ambiguity of using -1 both as an error indication (in ssize_t) and as a possibly castable result of pointer subtraction (in ptrdiff_t) is not likely to be a present in practice provided that size_t is as large as a pointer. If size_t is as large as a pointer, the only way that the mathematically correct value of P-Q could be (size_t)(-1) (aka SIZE_MAX) is if the object that P and Q refer to is of size SIZE_MAX, which, given the assumption that size_t is the same width as a pointer, implies that the object plus the following byte occupy every possible pointer value. That contradicts the requirement that some pointer value (NULL) be distinct from any valid address, so we can conclude that the true maximum size of an object must be less than SIZE_MAX.

这篇关于将sizeof()的结果分配给ssize_t的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆