防止溢出的stringsprintf

本文介绍在WinCE环境下如何解决_vscwprintf()不支持的问题,并提供了一种基于模板的字符串格式化方法stringsprintf,该方法适用于习惯使用sprintf或MFC中CString::Format的开发者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于WINCE不支持 _vscwprintf() 所以在使用字符串时候溢出是个大问题,当然如果可以忍受 stringstream的话,这个就不是问题了,对于习惯使用sprintf或者MFC中CString的Format的人们来说无疑是很郁闷的;

stringstream格式化输出可以采用如下操作

ostringstream ostr;
ostr << "sdfsaf" << "afsa";
string sp = ostr.str();

下面介绍一下stringsprintf, stringsprintf是参考他人的劳动成果所作的修改,主要改动就是改成了模板;

////////////////////////////////////////////stringsprintf.h//////////////////////////////////////////////

#include <cstdarg>
#include <sstream>
#include <string>

using namespace std;


template<typename _U>
basic_string<_U, char_traits<_U>, allocator<_U> > & stringprintf( basic_string<_U, char_traits<_U>, allocator<_U> > &s, const _U *fmt, ... )
{
s.clear();
//assert( s.empty() );

va_list ap;
va_start(ap, fmt);
const _U *next_c; // next character
while ( *fmt != _T('/0') )
{
switch ( *fmt )
{
case _T('%'):
{
next_c = fmt + 1;
switch ( *next_c )
{
case _T('/0'):
s += *fmt;
break;
case _T('%'):
s += _T('%');
++fmt;
break;
case _T('s'):
s += va_arg(ap, _U*);
++fmt;
break;
case _T('d'):
{
basic_ostringstream<_U, char_traits<_U>,allocator<_U> > oss;
oss << va_arg(ap, int);
s += oss.str();
++fmt;
break;
}
case _T('u'):
{
basic_ostringstream<_U, char_traits<_U>,allocator<_U> > oss;
oss << va_arg(ap, unsigned int);
s += oss.str();
++fmt;
break;
}
case _T('f'):
{
basic_ostringstream<_U, char_traits<_U>,allocator<_U> > oss;
oss << va_arg(ap, double);
s += oss.str();
++fmt;
break;
}
default:
assert( !_T("format unsupported.") );
break;
}

break;
}
default:
s += *fmt;
break;
}

++fmt;
}
va_end(ap);

return s;
}

### 解决 `sprintf` 中格式字符串不是字符串字面量的问题 在C编程中,当使用 `sprintf` 或其他类似的函数时,如果格式字符串不是一个常量字符串字面量而是变量,则可能会引入安全风险或运行时错误。为了防止这种情况发生并确保程序的安全性和稳定性,可以采取以下措施: #### 使用静态分析工具检测潜在问题 通过使用静态代码分析工具来扫描源码中的不安全调用模式是一个有效的方法。这些工具可以在编译前发现可能存在的漏洞。 #### 验证输入的有效性 对于动态构建的格式化字符串,在将其传递给 `sprintf` 之前应先验证其有效性。这可以通过预定义一组允许使用的格式说明符来进行匹配检查[^1]。 ```c #include <stdio.h> #include <string.h> int validate_format_string(const char *fmt) { const char *allowed_fmt[] = {"%d", "%s", "%f"}; size_t allowed_count = sizeof(allowed_fmt)/sizeof(*allowed_fmt); for (size_t i=0; i<strlen(fmt); ++i){ int valid = 0; if (fmt[i]=='%' && i+1<strlen(fmt)){ for(size_t j=0;j<allowed_count;++j){ if(strncmp(&fmt[i], allowed_fmt[j], strlen(allowed_fmt[j]))==0){ valid = 1; break; } } if (!valid || !strchr("diufFeEgGxXoOsSp%", fmt[++i])){ return 0; } } } return 1; } ``` 此函数会遍历传入的格式串,并尝试找到任何已知且被接受的形式;一旦遇到未知形式则立即返回失败标志。 #### 应用更安全替代方案 考虑采用更为安全的方式处理可变数据作为参数的情况,比如利用 `snprintf()` 来代替原始版本,并严格控制缓冲区大小以避免溢出攻击的风险。 另外还可以探索像 `asprintf()` 这样的GNU扩展功能(注意跨平台兼容性),它能够自动分配足够的内存空间用于存储最终的结果字符串。 #### 实施防御性编码实践 始终遵循良好的编程习惯,例如初始化所有局部变量、仔细审查第三方库的质量以及保持更新最新的补丁和修正等做法都可以帮助减少因误操作而导致的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值