如何处理跨平台 C 库中的 Unicode 路径?
How to deal with Unicode paths in a cross-platfrom C library?
我正在为 C 库做贡献。它有一个函数,该函数接受文件路径名的 char*
参数。作者大多是 UNIX 开发人员,这在 char*
主要表示 UTF-8 的 unix 上运行良好。 (至少in GCC,字符集可配置,默认为UTF-8。)
但是,char*
在 Windows 上表示 ANSI,这意味着目前无法在 Windows 上使用此库的 Unicode 路径名,其中 wchar_t*
应该被使用并且仅支持 UTF-16。 (A quick search on Whosebug 显示 ANSI Windows API 函数不能与 UTF-8 一起使用。)
问题是,处理这个问题的正确方法是什么?我们想出了各种方法来做到这一点,但我们都不是 Windows 专家,所以我们无法真正决定如何正确地做到这一点。我们的目标是库的用户应该能够编写可以在 unix 和 windows.
上运行的跨平台代码
在后台,该库有 #ifdef
s 来区分操作系统,因此它可以在 UNIX 上使用 POSIX 函数,在 [=48 上使用 Win32 APIs =].
到目前为止,我们已经提出了以下可能性:
- 提供单独的 windows 接受
wchar_t*
. 的函数
- 在 Windows 和
#ifdef
上需要 UTF-16 库头,以便函数在 Windows 上接受 wchar_t*
。
- 添加一个标志,告诉函数将给定的
char*
转换为 wchar_t*
并调用 widechar Windows APIs.
- 创建函数的变体,它采用文件描述符(或 Windows 上的文件句柄)而不是文件路径。
- 始终需要 UTF-8(甚至在 Windows 上),然后在函数内部,将 UTF-8 转换为 UTF-16 并调用 widechar Windows APIs。
选项 1-4 的问题在于它们需要用户自己有意识地照顾可移植性。选项 5 听起来不错,但我不确定这是否是正确的方法。
我也乐于接受可以解决此问题的其他建议或想法。 :)
由于可移植性是您的一个重要目标,我认为您的函数语义必须准确定义。除其他事项外,这意味着参数的类型和含义不会因平台而异。因此,如果您有一个接受常规 char
路径的函数,那么它应该在所有系统上接受此类路径,并且这些路径的预期编码应该明确定义(这不一定意味着 "the same" ).这排除了选项 (2) 和 (3)。
此外,可移植性要求相同 功能可在所有平台上使用;这排除了(1)。如果您的库仅提供基于流 and/or 文件描述符的方法,则选项 (4) 可能没问题,但它仅针对这些函数产生可移植性,而不是基于路径的函数. (请注意,流 (FILE *
) API 是由 C 定义的,而文件描述符是一个 POSIX 概念,不是 C 的原生概念。因此,原则上,流比文件描述符更具可移植性。)
(5) 可以工作,但它施加的约束比您实际需要的要强。函数定义预期的编码不是必需的(尽管它可以);它足以定义如何确定编码。
此外,您可以添加基于 wchar_t
的函数,这些函数在 无处不在 (与仅 Windows 相对)。这些对于 Windows 用户来说可能更方便。然而,与备选方案 (4) 类似,它仅针对那些功能提供可移植性。假设您不想放弃基于 char
的那些,您需要将此替代方案与 (5) 的一些变体配对。
我正在为 C 库做贡献。它有一个函数,该函数接受文件路径名的 char*
参数。作者大多是 UNIX 开发人员,这在 char*
主要表示 UTF-8 的 unix 上运行良好。 (至少in GCC,字符集可配置,默认为UTF-8。)
但是,char*
在 Windows 上表示 ANSI,这意味着目前无法在 Windows 上使用此库的 Unicode 路径名,其中 wchar_t*
应该被使用并且仅支持 UTF-16。 (A quick search on Whosebug 显示 ANSI Windows API 函数不能与 UTF-8 一起使用。)
问题是,处理这个问题的正确方法是什么?我们想出了各种方法来做到这一点,但我们都不是 Windows 专家,所以我们无法真正决定如何正确地做到这一点。我们的目标是库的用户应该能够编写可以在 unix 和 windows.
上运行的跨平台代码在后台,该库有 #ifdef
s 来区分操作系统,因此它可以在 UNIX 上使用 POSIX 函数,在 [=48 上使用 Win32 APIs =].
到目前为止,我们已经提出了以下可能性:
- 提供单独的 windows 接受
wchar_t*
. 的函数
- 在 Windows 和
#ifdef
上需要 UTF-16 库头,以便函数在 Windows 上接受wchar_t*
。 - 添加一个标志,告诉函数将给定的
char*
转换为wchar_t*
并调用 widechar Windows APIs. - 创建函数的变体,它采用文件描述符(或 Windows 上的文件句柄)而不是文件路径。
- 始终需要 UTF-8(甚至在 Windows 上),然后在函数内部,将 UTF-8 转换为 UTF-16 并调用 widechar Windows APIs。
选项 1-4 的问题在于它们需要用户自己有意识地照顾可移植性。选项 5 听起来不错,但我不确定这是否是正确的方法。
我也乐于接受可以解决此问题的其他建议或想法。 :)
由于可移植性是您的一个重要目标,我认为您的函数语义必须准确定义。除其他事项外,这意味着参数的类型和含义不会因平台而异。因此,如果您有一个接受常规 char
路径的函数,那么它应该在所有系统上接受此类路径,并且这些路径的预期编码应该明确定义(这不一定意味着 "the same" ).这排除了选项 (2) 和 (3)。
此外,可移植性要求相同 功能可在所有平台上使用;这排除了(1)。如果您的库仅提供基于流 and/or 文件描述符的方法,则选项 (4) 可能没问题,但它仅针对这些函数产生可移植性,而不是基于路径的函数. (请注意,流 (FILE *
) API 是由 C 定义的,而文件描述符是一个 POSIX 概念,不是 C 的原生概念。因此,原则上,流比文件描述符更具可移植性。)
(5) 可以工作,但它施加的约束比您实际需要的要强。函数定义预期的编码不是必需的(尽管它可以);它足以定义如何确定编码。
此外,您可以添加基于 wchar_t
的函数,这些函数在 无处不在 (与仅 Windows 相对)。这些对于 Windows 用户来说可能更方便。然而,与备选方案 (4) 类似,它仅针对那些功能提供可移植性。假设您不想放弃基于 char
的那些,您需要将此替代方案与 (5) 的一些变体配对。