全套 getopt 移植,支持 Unicode 和多字节 Microsoft Visual C、C++ 或 MFC 项目






4.87/5 (49投票s)
支持 getopt、getopt_long 和 getopt_long_only 以及 POSIXLY_CORRECT 环境变量标志
- 下载源代码 (2015)
- 下载源代码 (2022) 新
- 下载 Visual Studio 6 ANSI 项目 - 21.5 KB
- 下载 Visual Studio 6 MFC 项目 - 25.7 KB
- 下载 Visual Studio 2005 .NET ANSI 项目 - 13.8 KB
- 下载 Visual Studio 2005 .NET MFC 项目 - 17.7 KB
- 下载 Visual Studio 2008 .NET ANSI 项目 - 13.8 KB
- 下载 Visual Studio 2008 .NET MFC 项目 - 18.1 KB
- 下载 Visual Studio 2010 .NET ANSI 项目 - 15.7 KB
- 下载 Visual Studio 2022 .NET ANSI 项目 - 13.8 KB (新源代码)
引言
编写此软件之前,花费了大量时间搜索健壮的 Microsoft C 和 C++ 版 getopt
实现,但结果却令人失望。
此软件是 Free Software Foundation, Inc. getopt 库用于解析命令行参数的一个修改版本,其目的是提供一个对 Microsoft Visual C 更友好的派生版本。源代码提供了对 Unicode 和多字节构建的支持,并且支持 getopt
、getopt_long
和 getopt_long_only
。此外,该代码还支持 POSIXLY_CORRECT
环境变量标志。该库在定义 getopt
、getopt_long
和 getopt_long_only
函数时使用 _UNICODE
预处理器指令。这些函数分别映射回 getopt_a
/getopt_w
、getopt_long_a
/getopt_long_w
和 getopt_long_only_a
/getopt_long_only_w
。此改进是为了允许在多字节和 Unicode 项目中使用单个 DLL。
原始的 GNU 代码使用了包含大量特定于 Linux 环境的预处理器指令的多个头文件和实现文件,这些文件已被删除。在删除了不必要的依赖项后,将其精简为一个头文件和一个实现文件,可以将其编译成 DLL、LIB,或者直接包含到任何 Visual C、C++ 或 MFC 项目中。getopt
库可以被专有软件使用,但是;需要采取某些措施来确保专有代码遵守 Lesser GNU Public License(对非衍生作品)。请参阅本文档的许可部分,了解有关此软件许可方式的更多详细信息。
为了简洁起见,本文档不讨论如何使用 getopt
函数。任何不熟悉 getopt
函数使用的人都应参考 GNU 教程来使用 getopt
。
许可
由于 getopt
在 LGPL 许可下,在某些限制条件下可以免费用于专有软件。当将此库作为专有软件解决方案的一部分使用时,重要的是将库作为动态链接库 (DLL) 使用,并且不要静态链接或直接编译到专有源代码中。静态链接要求您的软件发布为 GPL。因此,通过动态链接库 (DLL) 将库单独引用,允许在不更改使用该库的专有软件的情况下修改和更新该 DLL;在这种情况下,专有软件被认为“使用”该库。因此,它不被视为衍生作品,可以根据任何许可自由分发。
预处理器定义
将 getopt
编译为动态链接库 (DLL) 需要预处理器定义 EXPORTS_GETOPT
。EXPORTS_GETOPT
的定义将内部预处理器定义 _GETOPT_API
设置为 __declspec(dllexport)
的值。将 getopt
编译为静态库 (LIB) 或直接在项目中包含源文件和头文件需要预处理器定义 STATIC_GETOPT
。STATIC_GETOPT
的定义会清除内部预处理器定义 _GETOPT_API
的值。编译使用 getopt.dll 的软件需要不使用任何库特定的预处理器定义。当不使用任何库特定的预处理器定义时,赋给内部预处理器定义 _GETOPT_API
的值是 __declspec(dllimport)
。
下面的代码段演示了上述逻辑
#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
#error "The preprocessor definitions of EXPORTS_GETOPT
and STATIC_GETOPT can only be used individually"
#elif defined(STATIC_GETOPT)
#pragma message("Warning static builds of getopt violate the Lesser GNU Public License")
#define _GETOPT_API
#elif defined(EXPORTS_GETOPT)
#pragma message("Exporting getopt library")
#define _GETOPT_API __declspec(dllexport)
#else
#pragma message("Importing getopt library")
#define _GETOPT_API __declspec(dllimport)
#endif
位于 getopt.h 中的以下代码段负责映射 getopt
、getopt_long
和 getopt_long_only
函数的正确版本。附加 _a 的 getopt
函数表示使用 char
类型的 ANSI 字符,而 Unicode 函数附加 _w 表示使用 wchar_t
类型的宽字符。
#ifdef _UNICODE
#define getopt getopt_w
#define getopt_long getopt_long_w
#define getopt_long_only getopt_long_only_w
#define option option_w
#define optarg optarg_w
#else
#define getopt getopt_a
#define getopt_long getopt_long_a
#define getopt_long_only getopt_long_only_a
#define option option_a
#define optarg optarg_a
#endif
提供的示例代码
为了帮助理解如何使用该代码,提供了多个版本供下载。提供的下载如下
- Visual Studio .NET 2022 ANSI 项目
- Visual Studio .NET 2010 ANSI 项目
- Visual Studio .NET 2008 ANSI 项目
- Visual Studio .NET 2008 MFC 项目
- Visual Studio .NET 2005 ANSI 项目
- Visual Studio .NET 2005 MFC 项目
- Visual Studio 6 ANSI 项目
- Visual Studio 6 MFC 项目
Using the Code
使用方法与 GNU getopt
完全相同。
#include <stdio.h>
#include <stdlib.h>
#include "tchar.h"
#include "getopt.h"
int _tmain(int argc, TCHAR** argv)
{
static int verbose_flag;
int c;
while (1)
{
static struct option long_options[] =
{
{_T("verbose"), ARG_NONE, &verbose_flag, 1},
{_T("brief"), ARG_NONE, &verbose_flag, 0},
{_T("add"), ARG_NONE, 0, _T('a')},
{_T("append"), ARG_NONE, 0, _T('b')},
{_T("delete"), ARG_REQ, 0, _T('d')},
{_T("create"), ARG_REQ, 0, _T('c')},
{_T("file"), ARG_REQ, 0 , _T('f')},
{ ARG_NULL , ARG_NULL , ARG_NULL , ARG_NULL }
};
int option_index = 0;
c = getopt_long(argc, argv, _T("abc:d:f:"), long_options, &option_index);
// Check for end of operation or error
if (c == -1)
break;
// Handle options
switch (c)
{
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
_tprintf (_T("option %s"), long_options[option_index].name);
if (optarg)
_tprintf (_T(" with arg %s"), optarg);
_tprintf (_T("\n"));
break;
case _T('a'):
_tprintf(_T("option -a\n"));
break;
case _T('b'):
_tprintf(_T("option -b\n"));
break;
case _T('c'):
_tprintf (_T("option -c with value `%s'\n"), optarg);
break;
case _T('d'):
_tprintf (_T("option -d with value `%s'\n"), optarg);
break;
case _T('f'):
_tprintf (_T("option -f with value `%s'\n"), optarg);
break;
case _T('?'):
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
if (verbose_flag)
_tprintf (_T("verbose flag is set\n"));
if (optind < argc)
{
_tprintf (_T("non-option ARGV-elements: "));
while (optind < argc) _tprintf (_T("%s "), argv[optind++]);
_tprintf (_T("\n"));
}
return 0;
}
将此代码与 C++ 预编译头文件一起使用
当在具有预编译头文件的 C++ 项目中静态使用此代码时,有必要将 getopt.c 重命名为 getopt.cpp,以规避以下编译器错误
"C1853 - Precompiled header file is from a previous version of the compiler,
or the precompiled header is C++ and you are using it from C (or vice versa)."
此外,必须将预编译头文件作为 getopt.c 或 getopt.cpp 文件的第一个 include。例如,如果您使用 "stdafx.h" 作为预编译头文件,则应如下所示
// File comments removed
#include "stdafx.h"
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include "getopt.h"
历史
- 2011 年 3 月 2 日 - 初始发布
- 2011 年 2 月 20 日 - 修复了 L4 编译器警告
- 2011 年 7 月 5 日 - 添加了
no_argument
、required_argument
、optional_argument
定义 - 2011 年 8 月 5 日 - 修复了导致运行时异常的非参数运行时错误
- 2011 年 8 月 9 日 - 添加了导出 DLL 和 LIB 函数的代码
- 2012 年 2 月 15 日 - 修复了在实现文件中缺少
_GETOPT_THROW
定义的问题 - 2012 年 8 月 3 日 - 为 char 和
wchar_t
字符创建了单独的函数,因此单个 DLL 可以同时支持 Unicode 和 ANSI - 2012 年 10 月 15 日 - 修改以匹配最新的 GNU 功能
- 2015 年 6 月 19 日 - 修复了由 option_a (255) 和 option_w (65535) 结构 val 变量导致的选项最大限制
- 2022 年 9 月 24 日 - 更新以匹配最新的 getopt 版本
- 2022 年 9 月 25 日 - 修复了 wchar_t* 的内存分配 (malloc 调用) 问题