api 特定类型定义(例如 GLsizei GLint GLvoid)的目的是啥?

Posted

技术标签:

【中文标题】api 特定类型定义(例如 GLsizei GLint GLvoid)的目的是啥?【英文标题】:What are the purpose of api specific typedefs such as GLsizei GLint GLvoid?api 特定类型定义(例如 GLsizei GLint GLvoid)的目的是什么? 【发布时间】:2010-11-21 08:31:36 【问题描述】:

API 特定类型定义(例如 GLsizei GLint GLvoid)的用途是什么?

我在 c 和 c++ 代码中随处可见这一点。基本类型通常使用库前缀/后缀进行类型定义。这背后的原因是什么?这是好习惯吗?我的程序应该自己做类似的事情吗?

乍一看,它似乎使代码的可读性降低了一点。您必须花点时间在脑海中将 GLint 转换为 int,这是一个简单的示例。

对我来说,像 UINT 这样的东西会做得更多,至少这会将 unsigned int 缩短为四个字母。

【问题讨论】:

【参考方案1】:

这不是关于缩短名称,而是关于可移植性。不同的平台需要对这些内容进行不同的 typedef。

在 Std-C 中,long 可能是 32 位或 64 位,具体取决于您的编译器/目标,因此不能安全地假定它是特定大小。因此,库作者将根据目标平台的知识对自己的类型进行类型定义,以保证一定的大小。

例如

#ifdef _WIN32
typedef __int64 INT64;  // long will not be 64 bit on Windows/VC.
#elif __GNU_C__
typedef long INT64;  // gcc typically uses 64 bit longs.
#elif // ... other platforms ...
...
#endif

如果编译器在未来版本中更改类型属性,则可以在一处编辑类型。

在过去,您还遇到过 int 大小可能为 16 或 32 位的典型情况,因此您不能在需要 DWORD 大小参数的代码中简单地使用原始 int 类型.

因此你有LPARAMWPARAM之类的东西。

它也被用作一种抽象形式。这就是为什么你会看到类似的 typedef

typedef int Handle;

因为虽然它现在是 int,但库作者保留稍后将其更改为其他任何内容的能力,例如 void *,或他们认为必要的任何其他类型。

但是客户端代码不需要知道它是一个int,因为这正是它目前的情况。客户端需要知道的只是将其传递给接受Handle 类型的函数。

Typedefs 还允许在编译时进行配置。例如。一些库可能有一个Real 实数类型。可以这样定义

#ifdef USE_DOUBLE_PREC
typedef double Real;
#else
typedef float Real;
#endif

并且库的用户可以在编译时选择设置/DUSE_DOUBLE_PREC 以获得双精度浮点支持,但重要的是无需更改库代码即可使其工作,因为它已被抽象。

【讨论】:

【参考方案2】:

在大多数情况下,当一个库定义了除了标准中类似命名类型之外没有保证属性的基本类型(想想INTGLintgintLPSTRu32u_int等),目的是:

    要“标记”您的代码,使其与库有很多紧密的依赖关系,因此在没有库的情况下重用您的代码会很痛苦,或者 不知道 C 标准为库的需要提供了适当的类型。

基于我最喜欢的原则之一“永远不要将可以用愚蠢来充分解释的事情归咎于恶意”,您可能会选择第 2 条,但这完全取决于您。

就个人而言,每当编写此类 API 时,我都会丢弃特定于库的类型并使用正确的自然类型(intchar *uint32_t 等)代替它们。如果我需要的话,可以很容易地调整我的代码以在没有库的情况下使用,并且代码对于不熟悉库的人来说更具可读性。

【讨论】:

用“C 标准”放慢速度,OpenGL 不仅适用于 C,而且与 C(或任何其他编程语言)无关。 :) 它不是“库”,而是 API。 不存在独立于语言的 API。当然,您可以尝试为多种语言制作外观相似的 API 版本,但结果喜忧参半。 (祝你好运,让 Brainf*ck 中的 OpenGL API 看起来一样。)在用特定语言实例化 API 时,您需要遵循该语言的约定,尤其是在类型方面。许多语言甚至没有类型,并且试图将GLint 的一些荒谬想法强加给它们而不是使用它们表示整数的本地方式会使该语言的用户大为震惊。 C 应该得到同样的尊重。 @Kos:这是一个标准,有一个规范。该规范以与语言无关的方式编写。 @R:平台 OpenGL 标头是用 C89 编写的。 C89 没有用于具有精确大小的整数类型的 typedef,例如 int32_t,因此它们必须定义自己的。另外,您的 1.) 是错误的。为什么会有人故意这样做?通常,每当您看到奇怪的东西时,您通常可以将其归咎于遗留代码,而不是恶意或愚蠢。 @R. - “如果你想强加“外部库 API”的同样荒谬的想法,实际上你必须执行 GLint 的荒谬想法。定义 GLint 的全部意义在于你不必须实际考虑在平台 XYZ 上常规 int 是 16 字节还是 32 字节还是 64 字节,这允许您以可移植的方式编写代码。 @Kos:如果GLint 的目的始终是 32 位,那么他们为它选择了一个非常糟糕的名称。阅读它,我希望它(如 Windows 的 INT 和 glib 的 gint)是自然大小的特定于平台的整数类型,可能总是定义为 int。 @Mads:如果您阅读我的回答,您会发现我建议 2 在提供它们之后是更好的解释。但是在某些情况下(肯定是 glib),它确实是 1。【参考方案3】:

如果需要以某种方式更改底层类型,它可以在一个地方更改 typedef,而不是在整个代码库中搜索和替换。然而,我也发现它比任何东西都更“噪音”,并且很少在现实生活中看到它需要它。

如果您碰巧在游戏中工作并且可能需要将您的游戏从/移植到 Nintendo DS,我见过的唯一一个不错的例子是浮点数,因为 DS 本身就可以使用定点数字。在这种情况下,您有一个特殊的浮点类型定义,因此它确实被类型定义为大多数平台上的浮点数和 DS 上的特殊定点类。

【讨论】:

定点和浮点的共同点太少了,以至于任何使用定点的代码都可能想要并且应该在任何地方都使用定点... 你会惊讶于在一个类中抽象它是多么容易。一家我从事合同工作的公司有这样一个引擎,它到处都有 BLAH_FLOAT(其中“BLAH”是他们公司的首字母缩写),因此他们的代码的 DS 和非 DS 版本和平共存。 我的意思不是实现,而是语义。例如,如果您的值是坐标,则它们应该是定点或浮点,并添加了 huge 偏差。否则精度会随位置而变化,在原点处比远离它处要高得多,这意味着行为不是平移不变的。

以上是关于api 特定类型定义(例如 GLsizei GLint GLvoid)的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章

glReadPixels 与 glPixelStore 的使用

介绍 GraphQL

运行 p1pp 时出现问题 - GLI.run 不再适用于 GLI-2

Lync 2010 API - 禁止 Toast 和对话窗口

如何获取特定版本的 Jquery(例如 3.2.1)的 TypeScript 定义文件?

swift-如何确保最初在哪个协议或类型中定义了特定属性?