int向string赋值潜在的溢出bug_int 类型用string接受会多出.0-程序员宅基地

技术标签: C/C++  编译器  c  string  null  linux  windows  GNU/Linux  

2011-11-1 wcdj

在程序中,有时会这样写代码:

#define XXX_ID 1
string str_result;
str_result = XXX_ID;
// ...
int iResultCode = atoi(str_result.c_str());
问题:这样的代码是否正确?

程序员本意的想法是iResultCode 应该为 1:

// error
str = 1; 
int iRes = atoi(str.c_str());// iRes == 1 ? , wrong! iRes == 0

实际的情况:
str = 数字,编译器会把这个数字解释为一个字符的ASCII值,从而把这个字符通过重载赋值运算符函数,赋值给str这个对象。因此,当str = 49; 时,str被赋值为字符 '1' 。然后,再通过atoi转换,iRes的值也为1。
// ok
str = 49; 
int iRes = atoi(str.c_str());// iRes == 1, ok

原因分析:

string str;
str = 1;
会调用:
_Myt& operator=(_Elem _Ch)// _Ch == 1
{	// assign 1 * _Ch
	return (assign(1, _Ch));
}

str = '1';
会调用:
_Myt& operator=(_Elem _Ch)// _Ch == 49
{	// assign 1 * _Ch
	return (assign(1, _Ch));
}

str = "1";
会调用:
_Myt& operator=(const _Elem *_Ptr)
{	// assign [_Ptr, <null>)
	return (assign(_Ptr));
}
一个存在bug的例子:
#include <iostream>
#include <string>
using std::string;
using namespace std;

int main(int argc, char* argv[])
{
	string str1, str2, str3, str4;
	str1 = "1";
	str2 = '1'; 

	/*
	str = (char)0;		// 0
	str = 1;			// 1
	str = 127;			// 127
	str = 128;			// -128 
	str = 255;			// -1
	str = 256;			// 0
	str = 257;			// 1
	*/
	// warning C4305: 'argument' : truncation from 'int' to 'char'
	// warning C4309: 'argument' : truncation of constant value
	str3 = 257;
	str4  = 1;// ok, no warning

	if (str3 == str4)
	{
		cout << "bug" <<endl;
	}

	cout << str1.c_str() << endl;
	cout << str2.c_str() <<endl;
	cout << str3.c_str() <<endl;
	cout << str4.c_str() <<endl;

    return 0;
}

结论:
用一个常量向string赋值的时候,这个常量的最大有效范围是char,即,0~127,超过这个范围就会被截断,而且用常量向string赋值然后再atoi转换回来,这个结果也是与我们的意愿不符的,并不会返回正确的值。因此,安全的做法应该是:先将int转换为char*,再赋值给string,这样我们想保存的最大数值(ID)可以为最大整型类型所表示的最大数值。
char szTmp[128]={0};
sprintf(szTmp, "%d", 257);
str3 = szTmp;

memset(szTmp, 0 ,sizeof(szTmp));
sprintf(szTmp, "%d", 1);
str3 = szTmp;

安全一点的做法是使用:snprintf(Linux)/ _snprintf(Windows)。

const int iLen = 128;
char szTmp[iLen] = {0};
_snprintf(szTmp, sizeof(szTmp)-1, "%d", 257);
str3 = szTmp;

memset(szTmp, 0 ,sizeof(szTmp));
_snprintf(szTmp, sizeof(szTmp)-1, "%d", 1);
str3 = szTmp;

注意:snprintf(Linux)与 _snprintf(Windows)对补0有不同,Linux下的自动补0,Windows的则不会。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/delphiwcdj/article/details/6924178

智能推荐

行列式因子、不变因子、初等因子、smith标准型、Jordan标准型、最小多项式的matlab实现_求解不变因子代码是什么-程序员宅基地

文章浏览阅读2.4w次,点赞13次,收藏74次。关于行列式因子、不变因子、初等因子、smith标准型、Jordan标准型、最小多项式的定义应用实例***行列式因子、不变因子、初等因子、smith标准型、Jordan标准型、最小多项式的matlab实现..._求解不变因子代码是什么

php $_SERVER 学习详解_$_server['content-type'];-程序员宅基地

文章浏览阅读881次。$_SERVER 示例keyvalue备注USERwww-data执行php的用户名HOME/var/www执行php的用户名的用户路径HTTP_COOKIEuser_cookie=test; user_test=cookie;用户cookieHTTP_ACCEPT_LANGUAGEen-US,en;q=0.9,zh-CN;q=0.8,zh;..._$_server['content-type'];

mac 加载www_mac assetbundle.loadfromfile-程序员宅基地

文章浏览阅读313次。mac下用assetbundle.loadfromfile 可以直接用application.streamingAsset但是用www则需要加前缀 file://_mac assetbundle.loadfromfile

Java基础25~XML和JSON解析-程序员宅基地

文章浏览阅读911次,点赞19次,收藏13次。将JSON字符串解析为对象集合:gson.fromJson(JSON字符串,new TypeToken(){}.getType());//Java对象转JSONSystem.out.println(“单个JSON:” + carJson);//JSON转Java对象System.out.println(“Java对象:” + car1);//Java集合转JSON。

shell全解-程序员宅基地

文章浏览阅读696次。Shell脚本是Linux和其他Unix-like操作系统中最重要的编程语言之一,它提供了丰富的工具和语法来自动化任务、管理系统和编写脚本。本文介绍了Shell脚本的基本语法、常用技术和安全问题,并提供了一些参考资料和学习建议。希望本文对初学者有所帮助,同时也鼓励读者进一步探索Shell脚本编程的深度和广度。_shell

文件的粘滞位(sticky bit)_粘性位文件-程序员宅基地

文章浏览阅读660次。文件的粘滞位(sticky)位是作什么用的? 普通文件的sticky位会被linux内核忽略, 目录的sticky位表示这个目录里的文件只能被owner和root删除 粘着位(Sticky bit) 如果用户对目录有写权限,则可以删除其中的文件和子目录,即使该用户不是这些文件的所有者,而且也没有读或写许可。粘着位出现执行许可的位置上,用t表示,设置了该位后,其它用户就不_粘性位文件

随便推点

linux ssh公钥文件,linux配置ssh公钥认证简介-程序员宅基地

文章浏览阅读493次。linux配置ssh公钥认证简介Linux操作系统诞生于1991 年10 月5 日(这是第一次正式向外公布时间)。Linux存在着许多不同的Linux版本,但它们都使用了Linux内核。下面是关于linux配置ssh公钥认证简介,希望大家认真阅读!一、生成和导入KEYA主机上生成key$ ssh-keygen -t rsa$ lsid_rsa id_rsa.pub将key导入到远程的B主机上,并修..._$ chmod 600 ~/.ssh/authorized_keys

Golang连接redis 并向redis写入和读取数据_go语言 redis.do往哪输入数据-程序员宅基地

文章浏览阅读6.2k次,点赞2次,收藏11次。文章导航目录第一步—下载包:第二步—开启Redis服务端和客户端:第三步—建立连接:运行结果:第一步—下载包:在连接Redis之前,我们需要安装一个包,在你的 gopath 目录下输入下面这个命令go get github.com/garyburd/redigo/redis如果不知道自己的gopath,输入 sudo vim /etc/profile 可以查看下载好以后,你会发现自己的 src文件 中多了一个 github.com 文件,这就说明下载好了我的目录结构是这样的:第二步—开启R_go语言 redis.do往哪输入数据

ORC发电实例分析-普惠280机组_orc朗肯循环发电技术的弊端-程序员宅基地

文章浏览阅读2.8k次。 前言 ORC发电项目能不能挣钱?或者在什么条件下能挣钱?是许多企业关注的问题,然而目前在国内还很难准确回答这个问题,因为可供参考的案例和数据非常有限,许多企业也是摸着石头过河。今天小编带来一个近年发生在美国的详细案例,供大家参考。该机组仅运行46天就被迫关停,项目的回收期长达46年,该项目有哪些我们可以学习的经验和教训呢?请随小编一起来看。 _orc朗肯循环发电技术的弊端

6、重建二叉树——剑指offer——找到根节点递归构建子树_构建当前节点,并递归构建左右子树-程序员宅基地

文章浏览阅读1.3k次。重建二叉树问题描述:已知前序和中序遍历结果,重构二叉树(不存在重复数据)。 本方法思想:前序遍历的第一个遍历是根,找到中序中的根所在的位置loc;在中序遍历中,在loc之前的是左子树,之后的是右子树(中序遍历的性质),递归的去重建左子树和右子树。持续更新...代码附下Java实现:递归方法:package 重建二叉树;/** * 已知前序和中序遍历结果,重构二叉树 * 前序的第一个是根..._构建当前节点,并递归构建左右子树

tnftp手册翻译-程序员宅基地

文章浏览阅读727次,点赞13次,收藏20次。请注意,如果此标记出现在 .netrc 文件中的任何非匿名用户中,而且有除此用户之外的任何人可读取 .netrc 文件,则tnftp将中止自动登录过程。然后,tnftp fork一个shell,使用**popen(3)**和提供的参数,并从stdout(stdin)读取(写入)。需要字节计数作为参数的命令(例如,hash、rate和xferbuf)支持参数上的可选后缀,该后缀更改参数的解释。ftp_proxy:在进行FTP URL请求时使用的FTP代理的URL(如果未定义,则使用标准的FTP协议)。

FSK调制_2FSK调制Matlab仿真_fsk调制 频谱-程序员宅基地

文章浏览阅读1.9w次,点赞11次,收藏103次。1.什么是2FSK调制2FSK(Frequency Shift Keying)为二进制数字频率调制(二进制频移键控),用载波的频率来传送数字信息,即用所传送的数字信息控制载波的频率。2FSK信号便是符号“0”对应于载频 f1,而符号“1”对应于载频 f2(与 f1 不同的另一载频)的已调波形,而且 f1 与 f2 之间的改变是瞬间的。传“0”信号时,发送频率为 f1 的载波; 传“1”信号时,..._fsk调制 频谱