在将程序从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位的差异相关推荐

  1. 查看linux机器是32位还是64位的方法

    查看linux机器是32位还是64位的方法: 1.方法1: file /sbin/init 或者 file /bin/ls /sbin/init: ELF 64-bit LSB executable, ...

  2. Linux系统查看系统是32位还是64位方法总结 in 创新实训

    这篇博客是总结.归纳查看Linux系统是32位还是64位的一些方法,很多内容来自网上网友的博客.本篇只是整理.梳理这方面的知识,方便自己忘记的时候随时查看. 方法1:getconf LONG_BIT ...

  3. 如何看linux是32位还是64位--转

    地址:http://hi.baidu.com/hehongrong/item/20c296bcf8d834432aebe3b2 如何看linux是32位还是64位 如何看linux是32位还是64位 ...

  4. linux查看证书位数,查看Linux系统是32位还是64位(getconf WORD_BIT误区)

    在写脚本(如:lnmp)时,经常需要判断linux操作系统是64bit还是32bit,如果是64bit执行这个命令(ln -s/usr/local/lib/libmcrypt.la /usr/lib6 ...

  5. 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: ...

  6. 如何查看Linux是32位还是64位

    查看linux机器是32位还是64位的方法: file /sbin/init 或者 file /bin/ls /sbin/init: ELF 64-bit LSB executable, x86-64 ...

  7. linux版本查看命令多少位,查看linux系统版本命令32位还是64位

    有的时候不知道我安装的是Linux 64位的还是Linux32位的,因为下载页面常常同时提供32位和64位版本的软件.所以弄清楚你的操作系统是32位的还是64位的十分重要,那么怎么查看linux系统版 ...

  8. linux是32还是64位,如何看linux是32位还是64位

    查看linux是多少位的几位方法: 查看linux机器是32位还是64位的方法: 方法一: file /sbin/init    或者   file /bin/ls 结果如下: /sbin/init: ...

  9. 查看linux主机多少位,linux怎么查看系统是32位还是64位的方法

    可以用命令"getconf LONG_BIT"查看, 如果返回的结果是32则说明是32位,返回的结果是64则说明是64位. 此外还可以使用命令"uname -a" ...

最新文章

  1. android 窗口缩放,Android界面整体缩放
  2. Python 【快手】短视频的自动上传与发布实例演示,同时支持抖音、哔哩哔哩、小红书、微视、西瓜视频、微信视频号等平台的视频自动化同步发布
  3. Android屏幕适应详解(一)
  4. 工业级服务器销售电话,工业级服务器
  5. 公里与英里的换算c语言函数_60迈=60码=60公里?这三者天壤之别,可别搞错了
  6. 翻译:Asp.net中多彩下拉框的实现
  7. C#开发高亮语法编辑器(一)——TextBox ,RichTextBox
  8. MySQL无中心化集群_MySQL Plus 如何做到无中心化、数据强一致性、秒级切换?
  9. Linux App Summit(LAS)社区 KDE Gnome
  10. UniWebView 3 使用心得
  11. html个人网页完整代码模板,静态 html 个人主页 模板
  12. 无防护等级的导电滑环有哪些类型和特征
  13. 非线性可视化(2)非线性相图
  14. 董事局主席董事长总裁首席执行官CEO总裁董事监事区别
  15. 基于scrapy的智联职位爬取
  16. Excel编程——自动换行
  17. 常用工具 [ubuntu 图像编辑软件]
  18. Spring、SpringMVC
  19. 如何实现PDF转Word
  20. win7系统无法开启telnet服务器,win7系统telnet出现错误怎么办?win7系统开启telnet出错的修复教程...

热门文章

  1. Openstack Nova 源码分析 — RPC 远程调用过程
  2. NR 5G MAC媒体接入控制
  3. Python3编写网络爬虫04-爬取猫眼电影排行实例
  4. selenium之 webdriver与三大浏览器版本映射表(更新至v2.29)
  5. linux服务器的日志管理
  6. 《CCNP安全防火墙642-618认证考试指南》——1.4节防火墙技术
  7. 如何在友好的情景下向用户索取手机权限?
  8. windows 7 在使用无线路由或者插线出现×××感叹号排除方法
  9. [LeetCode] Maximum Subarray
  10. jquery文件上传插件|进度条