如何在 C++ 中编写独立于平台的包装函数 [重复]
Posted
技术标签:
【中文标题】如何在 C++ 中编写独立于平台的包装函数 [重复]【英文标题】:How to write a platform independent wrapper function in C++ [duplicate] 【发布时间】:2020-05-31 09:18:00 【问题描述】:我正在使用 snprintf 将输出发送到缓冲区。使用 C++ 11 并用于桌面应用程序。
到目前为止,我只为 Windows 做这件事。但从现在开始,它必须支持不同的平台(Windows、Linux 和 Mac)
为了支持多平台,我打算写一个带有#if标签的包装函数。
但在这里我面临的挑战是,当从项目的不同位置调用 WrapperSprintf 时,参数的数量是不同的。
如何编写一个通用的包装器,可以在不同的地方使用不同的参数传递给 WrapperSprintf 函数?
我尝试了如下所示的包装函数。请帮助我如何继续:
void WrapperSprintf( char buffer, const char *format, ... )
#if defined(_WIN32)
_snprintf_s(buffer, sizeof(buffer), format,...);
#else
snprintf(buffer, sizeof(buffer), format, ...);
#endif
调用 WrapperSprintf 函数1:
char m_systemTime[20];
char* CUPSManager ::getSystemTime()
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
WrapperSprintf(m_systemTime,"%d-%d-%d :%d:%d:%d" , timeinfo ->tm_year +1900,
timeinfo ->tm_mon +1,
timeinfo->tm_mday,
timeinfo->tm_hour,
timeinfo->tm_min,
timeinfo->tm_sec);
return m_systemTime;
调用 WrapperSprintf 函数2:
void getDevicePath()
wstring strDevPath;
strDevPath = (LPCWSTR)cDevicePath;
char cDevPath[2048];
WrapperSprintf(cDevPath,"%ls", strDevPath.c_str());
int nPathLength = strlen(cDevPath);
...
【问题讨论】:
为什么需要一个包装器呢? MSVC 似乎支持snprintf
而没有 _
。 (并且_snprintf
不太安全;如果缓冲区不够长,它不会以空值终止字符串。)
查看va_list
,这是 C 捕获省略号的方式 (...
)。但是,为什么不使用 C++?
snprintf
是标准 C++ 函数。为什么你需要一个包装器?
这看起来像 C 代码。不是惯用的 C++ 代码。
@bolov snprintf()
(带有 n)是在 C++11 和/或 C99 中添加的。在此之前,它的实施并不标准。在编写可移植代码时,经常会看到配置检查以查看它是否以当前语言定义(因为它并不总是存在)。
【参考方案1】:
您可以在WrapperSprintf
中分别使用vsnprintf
和_vsnprintf
代替snprintf
和_snprintf
。这些函数使用可变参数列表。
参考:
http://www.cplusplus.com/reference/cstdio/vsnprintf/ https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l?view=vs-2019【讨论】:
【参考方案2】:我不会这样写的:
void WrapperSprintf( char buffer, const char *format, ... )
#if defined(_WIN32)
_snprintf_s(buffer, sizeof(buffer), format,...);
#else
snprintf(buffer, sizeof(buffer), format, ...);
#endif
这里不需要函数。您想要的是选择正确的功能。 而是这样做:
#if defined(_WIN32)
#define WrapperSprintf _snprintf_s
#else
#define WrapperSprintf snprintf
#endif
如果你想变得复杂并有能力重新排列参数,那么我们可以更进一步:
#if defined(_WIN32)
#define WrapperSprintf(buffer, size, ...) _snprintf_s(buffer, size, __VA_ARGS__)
#elif defined(_WIERDYSTEM)
#define WrapperSprintf(buffer, size, ...) wierdsnprintf(size, buffer, __VA_ARGS__)
#else
#define WrapperSprintf(buffer, size, ...) snprintf(buffer, size, __VA_ARGS__)
#endif
注意:__VA_ARGS__
必须至少匹配一个参数(即它不能匹配零)。因此,如果格式字符串中没有 %
标记,则将 if 用于“格式和格式参数”,因为可能存在零个“格式参数”。
【讨论】:
嗨@Martin York,感谢您提供详细信息。如果我像你提到的那样使用,它是否适用于 WrapperSprintf 中的不同参数。因为我从一个地方调用带有 7 个参数的 WrapperSprintf 函数,而从另一个地方调用带有 3 个参数的函数,就像我在问题中提到的那样。 @JohnPaulCoder 是的,...
(省略号)将匹配 1 个或多个参数,__VA_ARGS__
是如何将 ...
放置在输出端。
好的,谢谢。我会试试这个。但是,正如我建议的那样,我可以将您提供的代码放在一个公共文件中吗?这样我就可以从项目中的任何地方访问该功能?
@JohnPaulCoder 是的。只需将上述内容放在标题中即可。【参考方案3】:
如何在 C++ 中编写独立于平台的包装函数?
一种方法是阅读 C++ 标准(例如,n3337 用于 C++11),或者选择更新的标准 such as C++17,并坚持那里提到的功能。
另一种方法是在库之上编写 C++ 代码(例如 Qt 或 POCO 或 Boost 或 GTKmm)在您想要的所有平台之上提供抽象目标。
对于独立的 C++ 代码 cross-compiled 然后在嵌入式平台上运行(例如,FreeNOS 到 RaspBerry Pi 4 的某些端口,或最近的 android 或 AutoSar)这可能是一个技术挑战。
仔细阅读你的 C++编译器的文档
选择足够好的build automation 工具(例如GNU make 或Ninja 或其他)来运行您的C++ 编译器(和其他程序,可能是您的元程序)。
还可以考虑 C++ 程序的 Web 界面。
您会想到Wt 或Libonion 之类的工具包(或只是cpp-httplib)。当今大多数桌面操作系统都有一些网络浏览器(例如 Firefox,它本身是用 C++ 编码的)。
也考虑一些meta-programming 方法:
编写您的小程序,生成有助于可移植性的 C++ 代码。
SWIG 生成器可能有用或鼓舞人心(另请参见 ANTLR 解析器生成器、Qt moc、RefPerSys 项目、FLTK 工具包以获取灵感或搜索Quine 用 C++ 编写的程序)。 GPP 或 GNU m4 预处理器也很有用。您生成 C++ 代码的元程序可能使用 Python、Lua、Guile 或仅使用 C++ 等编写...
所以启用与可移植性相关的警告,如果可从您的 C++ 编译器获得。对于GCC,请阅读this。考虑在 2020 年底使用一些静态分析器(例如 Clang static analyzer、Frama-C++、Coverity、BugSeng 或 Bismon;请参阅 this draft 报告)来帮助您。
记住一句老话
没有portable代码之类的东西,只有一些移植软件....
署名忘记了,但我在上个世纪读过类似的东西
【讨论】:
嗨@Basile Starynkevitch,我想在为windows、linux服务的通用实用程序文件中编写一个通用函数,我们可以在整个项目中调用这个函数。我可以像我尝试的那样继续该功能(WrapperSprintf)吗? 针对哪个 C++ 标准(C++11、C++14、C++17、C++20)和哪个 C++ 目标实现(Android、您自己的 C++ 操作系统内核、Windows、 Linux,FreeRTOS,......)以及使用哪个 C++ 编译器或交叉编译器? 细节很重要,所以edit你的问题请。 适用于 C++ 标准 C++ 11,适用于桌面应用程序。 为什么不能用Qt,或者POCO,或者Boost?和哪个操作系统上的桌面(Linux不一样作为Windows或Android)? 请在您的问题中用书面英语解释这一点。如果您改进了您的问题,我可以投票重新提出问题。 使用Wt 并使用网络浏览器作为程序的界面怎么样? 请改进您的问题以上是关于如何在 C++ 中编写独立于平台的包装函数 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何在适用于 Android 和 iOS 的 C++ 跨平台库中正确链接 OpenCV?