linux c va_list 32位和64位的差异
在将程序从32位机器移植到64位机器的过程中经常出现一些奇奇怪怪的错误,这里记录一下在使用可变参数的过程中导致在32位机器上正常运行的程序移植到64位机器上之后出现段错误的发现过程以及解决方案。
首先看下面一段代码:
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>void parse(va_list ap)
{char* arg;arg = va_arg(ap, char*);std::cout << arg << std::endl<< strlen(arg) << std::endl;
}void test(const char* format, ...)
{va_list ap;va_start(ap, format);for (int i = 0; i < 2; i++){parse(ap);}va_end(ap);
}int main()
{test("hget %s %s", "abc", "123456");
}
在32位机器的运行结果如下:
abc
3
abc
3
在64位机器运行结果如下:
abc
3
123456
6
原因分析
出现上述结果的原因是由于va_list类型在32位和64位机器的类型不同导致的.
32位va_list
在32位上,va_list的定义为:
//注意,由于中间宏过多,这里省去了中间如_VA_LIST宏,直接给出实际定义。
typedef va_list char**;
64位va_list
在64位上va_list定义为一个结构体数组,并且数组中记录了可变参数被读的偏移量:
// Figure 3.34
typedef struct
{unsigned int gp_offset;unsigned int fp_offset;void * overflow_arg_area;void * reg_save_area;
} va_list[1];
当在32位机器上将va_list(char**)作为参数传递给函数的时候,该函数将从头开始读取该变长参数,还是使用va_list完毕并不记录当前va_list被读的偏移量,所以当第二次传入该va_list还是从头开始读取。程序异常分析
当在64为机器上将va_list(struct 数组)作为参数传递给函数的时候,该函数读取va_list完毕之后,将读取的偏移量记录在结构体中,由于其为数组传入函数,所以该被调用的函数改变了传入的va_list的偏移量。导致下次调用该函数从记录的偏移量开始读,造成不可预测或者内存越界等问题。
移植解决方案
将va_list初始化写到for循环内部,每次调用函数前都初始化va_list即可。
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>void parse(va_list ap)
{char* arg;arg = va_arg(ap, char*);std::cout << arg << std::endl<< strlen(arg) << std::endl;
}void test(const char* format, ...)
{for (int i = 0; i < 2; i++){va_list ap;va_start(ap, format);parse(ap);va_end(ap);}
}int main()
{test("hget %s %s", "abc", "123456");
}
总结:
1.每次函数调用了 va_list 变量 ap后, va_list内部指针发生改变, 此时想取以前的值,必须 va_end后重新va_start 到想要的值,不能自己直接操控指针,必须用对应的函数宏。
2.以下函数都会影响 ap 指针
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
此问题在32 64上都存在,虽然有时候感觉指针没有发生变化,但还是应该正规使用它
linux c va_list 32位和64位的差异相关推荐
- 查看linux机器是32位还是64位的方法
查看linux机器是32位还是64位的方法: 1.方法1: file /sbin/init 或者 file /bin/ls /sbin/init: ELF 64-bit LSB executable, ...
- Linux系统查看系统是32位还是64位方法总结 in 创新实训
这篇博客是总结.归纳查看Linux系统是32位还是64位的一些方法,很多内容来自网上网友的博客.本篇只是整理.梳理这方面的知识,方便自己忘记的时候随时查看. 方法1:getconf LONG_BIT ...
- 如何看linux是32位还是64位--转
地址:http://hi.baidu.com/hehongrong/item/20c296bcf8d834432aebe3b2 如何看linux是32位还是64位 如何看linux是32位还是64位 ...
- linux查看证书位数,查看Linux系统是32位还是64位(getconf WORD_BIT误区)
在写脚本(如:lnmp)时,经常需要判断linux操作系统是64bit还是32bit,如果是64bit执行这个命令(ln -s/usr/local/lib/libmcrypt.la /usr/lib6 ...
- linux 查看系统版本 32位 or 64位
1.#uname -a 如果有x86_64就是64位的,没有就是32位的 2.# uname -m x86_64 3.# arch x86_64 4.#file /bin/cat /bin/cat: ...
- 如何查看Linux是32位还是64位
查看linux机器是32位还是64位的方法: file /sbin/init 或者 file /bin/ls /sbin/init: ELF 64-bit LSB executable, x86-64 ...
- linux版本查看命令多少位,查看linux系统版本命令32位还是64位
有的时候不知道我安装的是Linux 64位的还是Linux32位的,因为下载页面常常同时提供32位和64位版本的软件.所以弄清楚你的操作系统是32位的还是64位的十分重要,那么怎么查看linux系统版 ...
- linux是32还是64位,如何看linux是32位还是64位
查看linux是多少位的几位方法: 查看linux机器是32位还是64位的方法: 方法一: file /sbin/init 或者 file /bin/ls 结果如下: /sbin/init: ...
- 查看linux主机多少位,linux怎么查看系统是32位还是64位的方法
可以用命令"getconf LONG_BIT"查看, 如果返回的结果是32则说明是32位,返回的结果是64则说明是64位. 此外还可以使用命令"uname -a" ...
最新文章
- android 窗口缩放,Android界面整体缩放
- Python 【快手】短视频的自动上传与发布实例演示,同时支持抖音、哔哩哔哩、小红书、微视、西瓜视频、微信视频号等平台的视频自动化同步发布
- Android屏幕适应详解(一)
- 工业级服务器销售电话,工业级服务器
- 公里与英里的换算c语言函数_60迈=60码=60公里?这三者天壤之别,可别搞错了
- 翻译:Asp.net中多彩下拉框的实现
- C#开发高亮语法编辑器(一)——TextBox ,RichTextBox
- MySQL无中心化集群_MySQL Plus 如何做到无中心化、数据强一致性、秒级切换?
- Linux App Summit(LAS)社区 KDE Gnome
- UniWebView 3 使用心得
- html个人网页完整代码模板,静态 html 个人主页 模板
- 无防护等级的导电滑环有哪些类型和特征
- 非线性可视化(2)非线性相图
- 董事局主席董事长总裁首席执行官CEO总裁董事监事区别
- 基于scrapy的智联职位爬取
- Excel编程——自动换行
- 常用工具 [ubuntu 图像编辑软件]
- Spring、SpringMVC
- 如何实现PDF转Word
- win7系统无法开启telnet服务器,win7系统telnet出现错误怎么办?win7系统开启telnet出错的修复教程...
热门文章
- Openstack Nova 源码分析 — RPC 远程调用过程
- NR 5G MAC媒体接入控制
- Python3编写网络爬虫04-爬取猫眼电影排行实例
- selenium之 webdriver与三大浏览器版本映射表(更新至v2.29)
- linux服务器的日志管理
- 《CCNP安全防火墙642-618认证考试指南》——1.4节防火墙技术
- 如何在友好的情景下向用户索取手机权限?
- windows 7 在使用无线路由或者插线出现×××感叹号排除方法
- [LeetCode] Maximum Subarray
- jquery文件上传插件|进度条