【问题标题】:Why is WinAPI so much different from "normal" C?为什么 WinAPI 与“普通”C 语言有很大不同?
【发布时间】:2009-12-02 15:52:22
【问题描述】:

我想知道为什么 WinAPI 与“普通”C 编程有如此大的不同?

我的意思是,在学校我了解到每个 C 程序都有一个 main() 函数(WinAPI 使用带有一些特殊参数的 WinMain),一些变量类型,如 int、long、char 等(WinAPI 使用 LPCSTR、BOOL、等)那么,为什么微软决定在他们的操作系统 API 上采用如此不同的方式呢?

当我看到我的第一个 WinAPI 程序时,我觉得它更像是一门新语言... ;)

【问题讨论】:

  • Inno - 我不确定为什么 MS 将#defines 用于许多变量类型。如果你想知道他们为什么决定这样做,我会给 Charles Petzold 发电子邮件。如果有人知道,他会的。
  • @J.Polfer:对参数类型使用别名对于库代码来说非常常见。它允许作者在保持源兼容性的同时更改界面中的特定类型。您仍然可以编译有效的 16 位 Windows 代码以针对 64 位版本的 Windows,即使基础类型例如WPARAMLPARAM 已多次更改。 BOOL 有不同的历史:当在 Windows 上开始工作时,C 语言中没有布尔类型。它是在 C99 中引入的。
  • 顺便说一句,甚至可以使用普通的main 函数编写 GUI 应用程序,尤其是在使用 QT、wxWidgets 等 GUI 框架时。... 多次这样做。如果我没记错的话,需要一些额外的编译器标志,如果使用 MSVS(自从我上次使用以来已经有一段时间了)。没有对 minGW 采取进一步行动。

标签: winapi


【解决方案1】:

最初的 Windows API 是在 25 年前的 1984-85 年设计的。匈牙利表示法风靡一时,因此将变量的类型放入声明中是要做的事情。例如,在纯 C 中,没有办法指示“远”指针,这是 LPCSTR 中的 LP 所指示的,但在 1985 年,区分常规指针和远指针非常重要。 (当 32 位窗口在 90 年代中期接管时,这种重要性就被搁置了,但语法仍然存在......)

此外,C 并没有真正区分指向 char 的指针和指向静态字符串的指针。因此 lpsz 类型。

最后,与 1984 年允许的普通 C 相比,它为参数带来了更强大、更一致的类型。至于 WinMain,这是因为 Windows 程序与命令行程序有很大的不同。如果您查看库,您可能会找到一个 main() 函数,它设置参数然后调用外部 WinMain 函数(即您的)。

【讨论】:

  • 1984-1985,那是一个没有 C 标准的时代,对吧?
  • 本机入口点签名是void __stdcall NoCRTMain(void),而不是传统的 C main() 函数。 C 运行时库会根据需要调用 WinMainmain
【解决方案2】:

有两个主要原因:

  • 复杂性。 C 语言是最小的,提供了可以构建更复杂架构的构建块。 LPCSTR、BOOL 和您在 Win32 中找到的其他类型是构建在 C 之上的 typedef 或结构。
  • 事件方向。通常教授 C 语言的前提是你的程序是主动的并且可以控制事物。在面向事件的环境中,例如 Windows(或任何其他基于 GUI 的操作系统),您的程序由操作系统调用,因此它通常位于循环中等待消息到达。

其他基于 GUI 的操作系统的 API 感觉可能与 Win32 不同,因为没有单一的解决方案,但它们要解决的问题是同一个。

【讨论】:

    【解决方案3】:

    微软的 Raymand Chen writes in his blog:

    虽然函数 WinMain 是 记录在平台 SDK 中,它是 不是平台的一部分。 相反,WinMain 是传统的 用户提供的入口点的名称 到 Windows 程序。

    真正的入口点在 C 中 运行时库,它初始化 运行时,运行全局构造函数,以及 然后调用您的 WinMain 函数(或 wWinMain 如果您更喜欢 Unicode 条目 点)。

    【讨论】:

      【解决方案4】:

      我想说大部分是风格问题。这些标准源于 Unix 世界,因此例如库函数具有短名称,并且没有大量的 typedef。我想这反映了 C 和 Unix 设计者的选择。另一方面,Windows 有LongFunctionNamesInMixedCaseLOTSOFTYPEDEFS*PTYPEDEFSFORPOINTERSTOO

      其中一些也是对必要性的感知。例如WinMain()nCmdShow 之类的东西,因为图形应用程序将调用ShowWindow(),我想他们希望能够将参数传递给新启动的进程。这是否真的需要可能是另一个问题。

      当然,有些 API 做了非常不同的事情。在 Windows 中,非常强调传递消息和基于每个线程处理消息。 CreateFile() 有很多 Unix 世界没有的标志,包括共享模式,它决定了当你打开一个文件时另一个进程可以做什么。

      【讨论】:

      • Windows 倾向于使用大信息结构使所有选项成为文件调用的一部分,Unix 使用对 ioctl 的调用。这可能是 windows 方法更容易的一个地方。
      • 在很多地方都是正确的,但 Windows 也有 ioctls。例如,用于设置重解析点或使文件稀疏。
      【解决方案5】:

      他们真的没有像你所说的那样“走这么不同的路”。

      WinMain() 只是 Windows 操作系统寻找的入口点。从概念上讲,它与 main() 没有什么不同。

      至于符号定义(LPCSTR、BOOL 等),部分原因是为了便于使用。例如,写LPCSTR 比写const char * 短。另一个例子是 C 语言不支持的 BOOL typedef。另一个原因是为了使开发人员免受底层硬件更改的影响,例如从 16 位到 32 位再到 64 位架构的更改。

      这个答案绝不应该被认为是详尽无遗的。这只是我在使用 Win32/MFC 进行的编程中注意到的几件事。

      【讨论】:

        【解决方案6】:

        Windows API 编程是事件驱动的,而在此之前,大多数 C 编程都是线性的。因此,WinMain() 是使用 OS 功能编写库的快捷方式 - 而 main() 是 C 语言的一部分。

        当我们谈到这个主题时,C 几乎没有内置类型,而且当时也没有多少方法可以指示它们。 windows“类型”(HWND、LPSTR、BOOL等)反映了windows编程中常用的数据类型,并试图向程序员指示数据类型将是什么。

        匈牙利表示法有点误用原始版本,因为在许多变量中有不必要数量的限定符。

        【讨论】:

          猜你喜欢
          • 2021-09-10
          • 1970-01-01
          • 2015-06-04
          • 2020-12-12
          • 2017-07-31
          • 2013-06-19
          • 2011-08-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多