【问题标题】:C++, Wrapper function for sprintf_sC++,sprintf_s 的包装函数
【发布时间】:2014-09-20 11:01:39
【问题描述】:

包含banned.h(微软安全工具之一)后,编译器警告我sprintf()函数不安全,MSDN中心给了我使用sprintf_s的建议,因为我的项目是跨平台的,我为 sprintf 函数写了一个包装器。

//safe function for sprintf();
void WrapperSprintf( char *buffer, const char *format, ... )
{
#ifdef _WIN32
    sprintf_s(buffer, sizeof(buffer), format,...);
#else
    sprintf(buffer, format, ...);
#endif
}

它在sprintf_s(buffer, sizeof(buffer), format,...); 行给我一个错误

错误 C2059:语法错误:'...'

有人知道如何为sprintf_s() 编写包装函数吗?

非常感谢。

【问题讨论】:

  • sizeof(buffer) 不符合您的预期,它的输出始终与sizeof(char*) 相同。
  • 这是使用宏的有效案例。 #define my_sprintf sprintf
  • 如果你使用stringstream,你可以完全放弃sprintf
  • 微软添加的所有这些xxx_s函数都有一个新的非常重要的参数:max_size。一些重载可以在没有它的情况下使用,但可以使用固定数组(例如 template int sprintf_s(char[N] buffer,...) 调用 sprintf_s(char* butter, size_t N, ...) ...之类的)。这是 strnlen 与 strlen 的模式。因此,您应该更改代码并始终传递“最大尺寸”参数并在非 Windows 平台中忽略它,或者在 Windows 平台中传递一些预定义的 max_size(如 1028)。
  • @πάνταῥεῖ 感谢您指出这一点:)

标签: c++ printf


【解决方案1】:

... 不会神奇地从函数声明转换为使用这些参数的其他调用。您必须包含变量参数的东西并使用它来调用下一个级别。

步骤基本上是:

  • 包括stdarg 标头。
  • 声明va_list
  • 致电va_start
  • 调用v*printf 函数之一。
  • 致电va_end

例如,这里有一个小程序,它演示了如何提供一个将格式化输出写入字符串的野兽,类似于您所追求的:

#include <stdio.h>
#include <stdarg.h>

void x (char *buf, char *fmt, ...) {
    va_list va;
    va_start (va, fmt);
    vsprintf (buf, fmt, va);
    va_end (va);
}

int main (void) {
    char buff[100];
    x (buff, "Hello, %s, aged %d", "Pax", 40);
    printf ("%s\n", buff);

    return 0;
}

我,我倾向于忽略微软关于sprintf 不安全的建议。如果您不知道自己在做什么,那么只有 any 工具可以说是不安全的。如果您想成为一名优秀的 C 程序员,您将了解该语言的局限性和弱点。

包括您在char* 上使用sizeof 的那个,期望它返回它指向的缓冲区的大小而不是指针的大小:-)

但是,如果您想成为 C++ 开发人员,请成为 C++ 开发人员。虽然 C 和 C++ 有很多共同点,但它们不是同一种语言。 C++ 主要包含许多 C 内容,因此您可以(大部分)获取已经编写的 C 代码并将其用于您的 C++ 应用程序。

换句话说,如果它是 C++ 应用程序,请使用 std::stringstd::stringstream(a) 而不是 char 数组和 s*printf 调用。

应该编写 C++ 代码,就好像 C 位不存在一样。否则,您更像是 C+ 程序员而不是 C++ 程序员 :-)


(a) 当然,知识渊博的开发人员可能已经避免 stringstream 内容中固有的冗长,并使用类似 fmtlib 的东西(与 @987654337 一样简洁@ 但 C++ 开发人员已经开始欣赏类型安全)。

特别是,因为它被购买到 C++20 中,在那里它将成为基础的一部分,可供所有人使用。

【讨论】:

  • 谢谢,paxdiablo,您的评论非常好,很有帮助。
  • “只有不知道自己在做什么才不安全”是真的,但是当你认为sizeof(buffer) 返回缓冲区的大小时,可悲的是,这意味着“不知道”你在做什么”。 C++ 格式化方法虽然需要做更多的工作,但避免了当您错误地使用sprintf 时可能发生的许多严重丑陋的事情。 C++ 是无情的,但 C 更不能容忍看似小错误。
  • 遗憾的是,这些函数必须默认弃用的原因是许多开发人员不知道他们在做什么,并且编写了损坏的代码。
  • sprintf 不安全!仅仅因为 MS 提供了它并不能让它变得不可忽视。它在模板和 SAL 之上运行 - 它们在编译和代码分析时检测到大多数错误。
  • 这不是不安全的如果你知道你在做什么!如果你确保你的缓冲区足够大以容纳你的格式字符串可以生成的最大的东西,它就和任何东西一样安全.当你弄错长度时,它甚至比使用“安全”变体更安全 :-) 你仍然必须知道如何正确使用所谓的安全变体,这与知道如何使用其他变体没什么不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
  • 2014-07-20
相关资源
最近更新 更多