【问题标题】:Is it appropriate to use off_t for non-byte offsets?将 off_t 用于非字节偏移是否合适?
【发布时间】:2013-07-13 00:26:00
【问题描述】:

假设我正在编写一个函数,该函数将float a[] 和一个偏移量写入此数组,并返回该偏移量处的元素。使用签名是否合理

float foo(float* a, off_t offset);

为了它?还是off_t 仅与字节偏移有关,而不是与任意元素大小的指针算术有关?即当偏移量是off_t 类型时说a[offset] 是否合理?

GNU C 库参考手册说:

off_t
     This is a signed integer type used to represent file sizes. 

但这并不能告诉我太多。

我的直觉是答案是否定的,因为在 a[offset] 中使用的实际地址是 a + sizeof(float) * offset 的地址,所以 "sizeof(float) * offset" 是一个@987654327 @ 和 sizeof(float) 是 size_t,两者都是带有“维度”的常量。

注意:偏移量可能为负数。

【问题讨论】:

  • 很确定访问指针的负偏移量被认为是邪恶的。
  • @zneak:也许吧,我不打算这样做,但a[-1] 是完全有效的代码。
  • @zneak 一点也不。为什么会这样。
  • @JamesKanze:试着编译一下看看。
  • @einpoklum 当然可以编译。这并不能使它有效。如果 a 被初始化为指向 C 样式数组的开头,则 a[-1] 无效,至少根据标准。

标签: c++ c types semantics offset


【解决方案1】:

你有什么理由不使用int?这是 C++ 中整数值的默认类型,应该使用 除非有充分的理由不这样做。

当然,一个很好的理由可能是它可能会溢出。如果 上下文是这样的,你最终可能会得到非常大的 数组,你可能想使用ptrdiff_t,它被定义(在 C 和 C++) 作为两个相减得到的类型 指针:换句话说,保证不会溢出(当 用作偏移量)适用于所有大小大于 1 的类型。

【讨论】:

  • 您能否引用一些官方消息来源建议“除非有充分的理由不使用,否则应使用int”?我不是要嘲讽你,我想看看理由。
  • @einpoklum “官方”来源是标准:在§3.9.1/2 中,普通的int 是自然类型,其他是“提供以满足特殊需要”。实际上,使用int 以外的任何类型都表示有特殊需要。也许增加范围,或节省空间。或者您需要无符号类型的模运算,或者正在进行位操作。 (使用无符号类型通常清楚地表明您没有处理算术数据。)
【解决方案2】:

您可以使用size_tptrdiff_t 作为索引的类型(您的第二个参数更像是浮点数组中的索引而不是偏移量)。

你的用途是一个索引,而不是一个偏移量。请注意,标准的offsetof 宏被定义为返回字节偏移量!

在实践中,您甚至可以使用 intunsigned,除非您认为您的数组可能包含数十亿个组件。

您可能希望#include <stdint.h>(或<cstdint> 使用最新的 C++)并为您的索引设置明确大小的类型,例如 int32_t

出于源代码可读性的原因,您可以定义

  typedef unsigned index_t; 

然后使用它,例如

  float foo(float a[], index_t i); 

我的意见是你应该使用int 作为你的索引类型。 (但要适当处理越界索引)。

【讨论】:

  • 定义index_t 类型是否常见?另外,如果我想要一个可能为负数的偏移量怎么办?
  • 他不能使用size_t,因为偏移量可以是负数。在内存中,正确的类型是ptrdiff_t,或者如果输入值的域或验证确保不存在溢出,则为int
  • size_t 是永远不会为负的数组索引的最佳类型(如果可以说任何一种类型是“最佳”)。对于可能为负数的索引,您可以使用ptrdiff_t 或(至少在 POSIX 上)ssize_t。见stackoverflow.com/questions/12175358/…stackoverflow.com/questions/8649018/…
  • @torek 这根本不正确。除非您进行位操作,否则应避免使用无符号类型。
  • @einpoklum 它有什么“狡猾”?它是 C 和 C++ 中的“默认”整数类型。从历史上看,这确实是一种默认。你不必声明它。即使在今天,除了字符类型之外,所有其他标准整数类型都是形式上的修饰符:unsigned 实际上是 unsigned int,等等。标准本身说普通 int 是自然整数类型,而其他的都是“提供以满足特殊需要”。
【解决方案3】:

我会说这是不合适的,因为

  1. off_t (打算)用于表示文件大小
  2. off_t 是有符号类型。

我会选择size_type(通常是size_t 的“typedef”ed 名称),这是标准容器使用的名称。

【讨论】:

  • std::vector<T>::size_typesize_t 的 typedef(存在于 C 中)。 size_type 不作为独立类型存在。
  • 但是 off_t 怎么能代表文件大小呢?偏移量不是大小……偏移量可以是负数,而大小不能。
  • @einpoklum,它用于文件操作,例如fseek/lseek。另一方面,size_t 被定义为能够容纳平台上任何数组的最大大小。听起来更像您正在寻找的东西。
  • @einpoklum 据我所知,负值 (-1) 用于错误报告(例如:linux.die.net/man/2/lseek
  • 所以,在这种情况下,off_t 完全不在讨论范围内......(请原谅双关语)。我认为size_t 在语义上仍然不合适。
【解决方案4】:

也许答案是使用ptrdiff_t?它...

  • 可以是负数;
  • 暗示差异不是以字节为单位,而是以任意大小为单位,具体取决于元素类型。

你怎么看?

【讨论】:

  • 虽然其他人在我之后建议ptrdiff_t,但他们都发表了我不太同意的声明。对不起,伙计们。
猜你喜欢
  • 2016-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 2020-11-27
相关资源
最近更新 更多