详解-C语言可变参数-va-list和-vsnprintf及printf实现

合集下载

格式化输出函数:printf,f...

格式化输出函数:printf,f...

格式化输出函数:printf,f...总览 (SYNOPSIS)#include <stdio.h>int printf(const char *format, ...);int fprintf(FILE *stream, const char *format, ...);int sprintf(char *str, const char *format, ...);int snprintf(char *str, size_t size, const char *format, ...);#include <stdarg.h>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);描述 (DESCRIPTION)printf 系列函数根据下述的 format 参数生成输出内容. printf 和 vprintf 函数把输出内容写到 stdout, 即标准输出流; fprintf 和 vfprintf 函数把输出内容写到给定的 stream 流(字符流设备); sprintf, snprintf, vsprintf 和 vsnprintf 函数把输出内容存放到字符串 str 中.这些函数由格式字符串 format 参数控制输出内容, 它指出怎么样把后面的参数 (或通过 stdarg 的变长参数机制访问的参数) 转换成输出内容.这些函数返回打印的字符数量 (不包括字符串结尾用的`/0'). snprintf 和 vsnprintf 的输出不会超过 size 字节 (包括了结尾的 `/0'), 如果因为这个限制导致输出内容被截断, 则函数返回 -1.格式字符串 (format 参数) 由零到多个指令组成: 普通字符(除 % 外), 它们被原封不动的送到输出流; 以及格式转换说明(conversion specification), 每个格式转换说明都会从后面提取零到多个参数. 格式转换说明由 % 字符引导开始. 参数必须正确的对应到格式转换符 (conversion specifier) 上. 下述字符按顺序列在 % 后面:*零个或多个下列标志:#指出数值应该转换成 "其他形式". 对于 c, d, i, n, p, s, 和 u 格式转换, 这个选项没有影响. 对于 o 格式转换, 数值的精度被提高, 使输出字符串的第一个字符为零 (除非打印一个零值时, 明确定义精度为零). 对于 x 和 X 格式转换, 非零数值前面会添加 `0x' 字符串(或 X 格式转换的 `0X' 字符串). 对于 e, E, f, g, 和 G 格式转换, 其结果始终含有一个十进制小数点, 即使后面没有数字 (一般说来, 只有当格式转换后, 小数点后面有数字时才显示小数点). 对于 g 和 G 格式转换, 将不删去结果末尾的零, 其他情况下这些零应该删掉. 0指出用零填充结果. 所有的格式转换, 除了 n, 转换结果的左边用零填充, 而不是空格. 如果数值转换时给定了精度, (d, i, o, u, i, x, 和 X), 则忽略 0 标志.-(负位宽标志) 指出转换结果必须在位边界上向左边对齐. 除了 n 格式转换, 转换结果的右边用空格填充, 而不是在左边填充空格或零. 如果同时给出了 - 和 0 , 则 - 覆盖 0 .' '(空格) 指出在通过有符号数(signed) 格式转换 ( d, e, E, f, g, G, 或 i ) 产生的正数前面留一个空格.+指出有符号数格式转换产生的结果前面始终有一个正负符号. 如果同时给出了 + 和空格, 则 + 覆盖空格.'指出在数字参数中, 如果 locale 给出相关信息, 输出结果将被分组. 注意, 许多版本的 gcc不能理解这个选项, 因而会产生一个警告.*一个可选的十进制数, 指出最小的位宽. 如果格式转换后产生的字符数少于位宽, 则左边用空格填充 (或者填充右边, 如果给出了向左对齐标志), 直到填满指定的位宽.*一个可选的精度, 格式是一个句号(`.') 后面跟着一个可选的数字. 如果没有给出这个数字, 则精度取为零. 这样就指定了 d, i, o, u, x, 和 X 格式转换显示的最小位数, e, E, 和 f 格式转换小数点后面显示的位数, g 和 G 格式转换显示的最大有效位数(significant digits), 或 s 格式转换打印某个字符串的最多字符数目.*可选的字符 h, 指出后面的 d, i, o, u, x, 或 X 格式转换对应为 short int 或 unsigned short int 的参数, 或者是后面的 n 格式转换对应为指向 short int 参数的指针.*可选的字符 l (ll) 指出后面的 d, i, o, u, x, 或 X 格式转换应用到指向 long int 或 unsigned long int 参数的指针, 或者后面的 n 格式转换对应为指向 long int 参数的指针. Linux 提供和 ANSI 不兼容的双 l 标志, 作为 q 或 L 的同义词. 因此 ll 可以结合浮点格式转换使用. 但是强烈反对这个用法.*字符 L 指出后面的 e, E, f, g, 或 G 格式转换对应 long double 参数, 或者让后面的 d, i, o, u, x, 或 X 格式转换对应 long long 参数. 注意 long long 没有在 ANSI C 中声明, 因此不能够移植到所有的体系平台上.*可选的字符 q 等于 L. 参考 STANDARDS 和 BUGS 节关于 ll, L,和 q 的叙述.*字符 Z 指出后面的整数 (d, i, o, u, x, 或 X) 格式转换对应 size_t 参数.*指出采用格式转换类型的字符.可以用星号 `*' 代替数字指定域宽或精度, 也可以两者同时指定. 这种情况下要求用一个 int 参数指出域宽或精度. 负域宽被认为是正域宽跟在向左对齐标志后面; 负精度被认为是精度丢失.格式转换符(specifier) 及其含义如下:diouxX将 int 形 (或合适的变量) 参数转换输出为有符号十进制数 (d 和 i), 无符号八进制数 (o), 无符号十进制数(u), 或者无符号十六进制数 (x 和 X). x 格式转换用小写字母 abcdef ; X 格式转换用大写字母 ABCDEF .精度值 (如果给出) 指出必须显示的最少数字; 如果转换结果少于这个要求, 则用零填补转换结果的左边.eE将 double 参数舍入后转换为 [-]d.ddde/*(Pmdd 的格式, 这个格式的小数点前面有一位数字, 后面表示精度; 如果没有指出精度, 则意味着精度是 6; 如果精度是 0, 则不显示小数点. E 格式转换使用字母 E (而不是 e) 要求引入指数. 指数至少包含两个数字; 如果值是零, 则指数是 00.f将 double 参数舍入后转换为 [-]ddd.ddd 的十进制表达式, 这个格式小数点后面的数字表示精度. 如果没有指出精度, 则意味着精度是 6; 如果显式给出精度是 0, 则不显示小数点. 如果显示了小数点, 则小数点前面至少有一位数字.g将 double 参数以 f 或 e (或者 G 格式转换的 E 标志) 的形式转换. 其精度指出有符号数字的数目. 如果没有指出精度, 则默认为 6; 如果精度是零, 则按 1 处理. 如果格式转换后其指数小于 -4 或者大于等于其精度, 则使用 e 形式. 转换结果消除了分数部分末尾的零; 小数点前面至少有一位十进制数字.c将 int 参数转换为 unsigned char, 然后输出对应的字符.s认为 ``char *'' 参数是指向字符形数组的指针 (指向字符串). Printf 输出数组内的字符, 直到遇上 (但不包括) 结束字符 NUL ; 如果给出了精度值, printf 不会输出多于这个值的字符, 也不需要提供 NUL 结束符; 如果没有给出精度值, 或精度值大于数组长度, 则数组内一定要包括一个 NUL 字符.p将以十六进制数打印 ``void *'' 指针参数 (就象是 %#x 或 %#lx). n将目前已经输出的字符数目存储在 ``int *'' (或变量) 指针参数指向的地址. 不转换任何参数.%输出一个 '%'. 不转换任何参数. 完整的写法是 `%%'.不指定域宽或偏小的域宽不会导致内容被截断; 如果转换结果的长度超过其域宽, 则域宽会扩大到容下完整的结果.示例 (EXAMPLES)以 `Sunday, July 3, 10:02' 格式显示日期, 其中 weekday 和 month 是字符串指针:#include <stdio.h>fprintf(stdout, "%s, %s %d, %.2d:%.2d/n", weekday, month, day, hour, min);显示五位十进制数:#include <math.h>#include <stdio.h>fprintf(stdout, "pi = %.5f/n", 4 * atan(1.0)); //atan( ) 函数返回数值表达式的反正切弧度值。

vsprintf用法

vsprintf用法

vsprintf⽤法vsprintf()函数中的⾃变量是位于数组中的,数组元素的字符串之前都要加上百分号(%)。

这个函数是“⼀步⼀步[step-by-step]”按顺序执⾏。

在第⼀个%后,将插⼊第⼀个数组元素;在第⼆个%后,将插⼊第⼆个数组元素,依次类推。

vsprintf是sprintf的⼀个变形,它只有三个参数。

vsprintf⽤於执⾏有多个参数的⾃订函式,类似printf格式。

vsprintf的前两个参数与sprintf相同:⼀个⽤於保存结果的字元缓冲区和⼀个格式字串。

第三个参数是指向格式化参数阵列的指标。

实际上,该指标指向在堆叠中供函式呼叫的变数。

va_list、va_start和va_end巨集(在STDARG.H中定义)帮助我们处理堆叠指标。

本章最後的SCRNSIZE程式展⽰了使⽤这些巨集的⽅法。

使⽤vsprintf函式,sprintf函式可以这样编写:int sprintf (char * szBuffer, const char * szFormat, ...){ int iReturn ; va_list pArgs ; va_start (pArgs, szFormat) ; iReturn = vsprintf (szBuffer, szFormat, pArgs) ; va_end (pArgs) ; return iReturn ;}va_start巨集将pArg设置为指向⼀个堆叠变数,该变数位址在堆叠参数szFormat的上⾯。

函数名: vsprintf功能: 送格式化输出到串中⽤法: int vsprintf(char *string, char *format, va_list param);程序例:#include <stdio.h>#include <conio.h>#include <stdarg.h>char buffer[80];int vspf(char *fmt, ...){va_list argptr;int cnt;va_start(argptr, fmt);cnt = vsprintf(buffer, fmt, argptr);va_end(argptr);return(cnt);}int main(void){int inumber = 30;float fnumber = 90.0;char string[4] = "abc";vspf("%d %f %s", inumber, fnumber, string);printf("%s\n", buffer);return 0;}va_list ap;int len;va_start(ap, format);vsprintf(_this->printfBuf, format, ap)va_end(ap);请问vsprintf的作⽤⼲什么啊?根据上⾯代码能详细介绍下吗?谢谢!===============================把参数 ap 按照 format 指定的格式,写到 _this->printfBuf 中基本和 sprinf 类似 ......⽐如上⾯给的例⼦:vsprintf(buffer, fmt, argptr);fmt="%d %f %s"就是把后⾯的参数按照 "%d %f %s" 这个格式输出到 buffer 中。

_vsnprintf用法

_vsnprintf用法

_vsnprintf⽤法_vsnprintf,C语⾔库函数之⼀,属于可变参数。

⽤于向字符串中打印数据、数据格式⽤户⾃定义。

头⽂件:#include <stdarg.h>函数声明:int _vsnprintf(char* str, size_t size, const char* format, va_list ap);参数说明:char *str [out],把⽣成的格式化的字符串存放在这⾥.size_t size [in], str可接受的最⼤字节数,防⽌产⽣数组越界.const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。

va_list ap [in], va_list变量. va:variable-argument:可变参数函数功能:将可变参数格式化输出到⼀个字符数组。

⽤法类似于vsprintf,不过加了size的限制,防⽌了内存溢出(size为str所指的存储空间的⼤⼩)。

返回值:执⾏成功,返回写⼊到字符数组str中的字符个数(不包含终⽌符),最⼤不超过size;执⾏失败,返回负值,并置errno.[1]备注:linux环境下是:vsnprintfVC6环境下是:_vsnprintf#include <stdio.h>#include <stdarg.h>int mon_log(char* format, ...){char str_tmp[50];int i=0;va_list vArgList; //定义⼀个va_list型的变量,这个变量是指向参数的指针.va_start (vArgList, format); //⽤va_start宏初始化变量,这个宏的第⼆个参数是第⼀个可变参数的前⼀个参 //数,是⼀个固定的参数.i=_vsnprintf(str_tmp, 50, format, vArgList); //注意,不要漏掉前⾯的_va_end(vArgList); //⽤va_end宏结束可变参数的获取return i; //返回参数的字符个数中间有逗号间隔}//调⽤上⾯的函数void main() { int i=mon_log("%s,%d,%d,%d","asd",2,3,4); printf("%d\n",i); }输出9。

vsnprintf函数

vsnprintf函数

vsnprintf函数详解1. 定义和用途vsnprintf函数是C语言标准库中的一个函数,其原型如下:int vsnprintf(char *str, size_t size, const char *format, va_list ap);vsnprintf函数用于将可变参数列表(va_list)根据格式化字符串(format)进行格式化,并将结果输出到一个字符数组(str)中,最多输出size-1个字符。

2. 参数解释•str:指向一个字符数组的指针,用于存储格式化后的结果。

•size:字符数组的大小,即可以存储的最大字符数。

注意,这里不包括结尾的空字符’\0’。

•format:格式化字符串,用于控制如何对可变参数进行格式化输出。

•ap:va_list类型的可变参数列表。

3. 工作方式vsnprintf函数根据format字符串中的格式说明符来确定如何处理可变参数列表,并将结果写入str指向的字符数组中。

3.1 格式说明符在format字符串中,以百分号(%)开头的部分被视为格式说明符。

常见的格式说明符有: - %d 或 %i:按照有符号十进制整数形式输出。

- %u:按照无符号十进制整数形式输出。

- %x 或 %X:按照无符号十六进制整数形式输出。

- %f 或 %F:按照浮点数形式输出。

- %s:按照字符串形式输出。

- %c:按照字符形式输出。

除了以上常见的格式说明符外,还有很多其他类型的格式说明符,可以用于更复杂的格式化需求。

3.2 可变参数列表vsnprintf函数使用va_list类型的可变参数列表来传递额外的参数。

可变参数列表是一种特殊的数据类型,用于表示不定数量和类型的参数。

在调用vsnprintf函数之前,必须通过宏va_start初始化可变参数列表,指定可变参数列表中第一个可选参数的名称。

在使用完可变参数列表后,需要通过宏va_end结束可变参数列表。

3.3 格式化结果输出vsnprintf函数将根据format字符串中的格式说明符和相应的可变参数对其进行格式化,并将结果写入str指向的字符数组中。

snprintf 替换函数

snprintf 替换函数

snprintf 替换函数
如果需要替换snprintf函数,可以使用标准库中的snprintf函数的可替代函数vsnprintf。

这是一个可变参数函数,可以接受一个va_list参数,因此可以模拟snprintf的行为。

以下是一个简单的示例:
```cpp
#include <stdarg.h>
#include <stdio.h>
int my_snprintf(char* str, size_t size, const char* format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf(str, size, format, args);
va_end(args);
return result;
}
```
在上述示例中,我们定义了一个名为my_snprintf的函数,它接受与snprintf相同的参数。

在函数体中,我们使用vsnprintf函数来处理实际的格式化操作,并返回结果。

您可以将my_snprintf函数与您的代码一起使用,替换原有的snprintf函数。

请注意,这只是一个简单的示例,您可能需要根据自己的需求和平台特性进行相应的修改和调整。

C++11标准库中cstdio头文件新增的5个格式化IO函数学习

C++11标准库中cstdio头文件新增的5个格式化IO函数学习

C++11标准库中cstdio头⽂件新增的5个格式化IO函数学习刚开始学⽹络编程,稍微扩展书上的简单C/S程序时,发现以前太忽略标准I/O这⼀块,查官⽹发现C++11新增了⼏个格式化I/O函数。

snprintf 将格式化输出写⼊到有⼤⼩限制的缓存中vfscanf 从流中读取数据到可变参数列表中vscanf 读取格式化数据到可变参数列表中vsnprintf 从可变参数列表中写⼊数据到有⼤⼩限制的缓存中vsscanf 从字符串中读取格式化数据到可变参数列表中主要谈谈snprintf,后⾯4个都是辅助可变参数列表的。

int snprintf ( char * s, size_t n, const char * format, ... );百度⼀下会发现⼀些过时的⽂章写到VC上是_snprintf⽽gcc上是snprintf,VC的_snprintf不会在复制完的字符串后⾯补上⼀个'\0'。

这是很多C新⼿会在Win平台会出现烫烫烫的原因,因为输出字符数组时没有遇到'\0'结尾,所以会⼀直输出,甚⾄是未初始化的内存,默认为0xcccccccc,变成字符串就是“烫烫烫”。

具体参考⽂章但是新标准已经将snprintf标准化了函数签名如下,所以也不⽤担⼼那个问题。

snprintf和sprintf功能基本⼀致,但是更安全,参数多了⼀个size_t n,代表写⼊缓存的数据⼤⼩。

⽐如char buf[10]; 如果n超过10,就会在编译期提醒错误,所以在VS中写C++,如果使⽤fopen等函数会编译不通过,提⽰你使⽤fopen_s(类似的还有其他_s后缀的函数)等安全(safe)函数(会在编译期检测错误)的原因。

题外话,解决⽅案,当然更简单的做法就是每次新建C++项⽬时把默认SDL Check⼀栏的勾勾去掉。

回正题,也就是说,除了跟sprintf⼀样,到格式化字符串结尾会停⽌写⼊缓存外,当写⼊字符数量到达n时也会停⽌写⼊缓存,防⽌越界。

c++可变参数列表

c++可变参数列表
va_list valist 可作为函数声明中的可变参数部分 int Log_fatal(char *c_filename, long c_fileline, char *format, va_list valist) __VA_ARGS__ 标识符只能出现在可变参数宏中的替换列表中 #define htLogDebugC(...) htLog(HTLOG_LEVEL_DEBUG,__FILE__,__LINE__,__VA_ARGS__) 将可变参数从宏--->函数--->函数 #define htLogDebug(pLog,...) (pLog)->LogOut(HTLOG_LEVEL_DEBUG,__FILE__,__LINE__,__VA_ARGS__) int32_t LogOut(uint32_t Level, const char *FileName, long FileLine, char *Format, ...) ; LogOut函数中将...可变参数列表处理: va_list ap; va_start(ap, FileLine); Log_debug((char*)FileName, FileLine, va_arg(ap, char*),ap); //调用另一个函数 va_end(ap); //Log_debug的声明 //int Log_debug(char* c_filename, long c_fileline, char *format, va_list valist) 其他函数 直接使用valist即可 WriteLogBase( (_g_) , c_filename , c_fileline , _log_level_ , format , valist ) ;
博客园 用户登录 代码改变世界 密码登录 短信登录 忘记登录用户名 忘记密码 记住我 登录 第三方登录/注册 没有账户, 立即注册

c语言可变参数用法

c语言可变参数用法

c语言可变参数用法C语言可变参数用法C语言作为一种高度灵活和强大的编程语言,为程序员提供了丰富的编程工具和特性。

其中之一就是可变参数,它允许函数接受不定数量的参数。

在本文中,我们将深入探讨C语言可变参数的用法和实现。

一、什么是可变参数首先,我们需要了解可变参数的概念。

在C语言中,可变参数是指一个函数接受不定数量的参数。

这意味着我们可以使用不同数量的参数来调用函数,而函数内部可以根据需要处理这些参数。

这为我们处理各种情况和需求带来了极大的灵活性。

二、可变参数的声明在C语言中,使用可变参数之前,我们需要在函数声明中使用`...`来表示参数的可变性。

例如,下面是一个使用可变参数的函数声明:cint sum(int count, ...);在这个例子中,`...`表明该函数将接受可变数量的参数,而`count`参数指定了传递给函数的参数数量。

三、可变参数的使用接下来,我们将了解如何在函数内部使用可变参数。

在C语言中,我们可以使用`stdarg.h`头文件中的一些宏来处理可变参数。

让我们逐一了解这些宏。

1. `va_list`类型`va_list`类型用于定义一个变量来保存可变参数列表。

我们可以通过`va_start`宏初始化这个变量。

cvoid func(int count, ...) {va_list args;va_start(args, count);...在上面的例子中,我们使用了`va_list`类型的变量`args`来保存可变参数。

2. `va_start`宏`va_start`宏用于初始化`va_list`类型的变量。

它接受两个参数,第一个参数是保存可变参数的`va_list`类型变量,第二个参数是最后一个固定参数的标识符。

cvoid func(int count, ...) {va_list args;va_start(args, count);...在上面的例子中,我们使用了`va_start(args, count)`来初始化`args`变量,并指定`count`作为最后一个固定参数的标识符。

vsnprintf函数

vsnprintf函数

vsnprintf函数vsnprintf函数是C语言中非常常用的一个函数,它是对标准库函数snprintf的一个扩展。

vsnprintf函数的作用是将可变参数列表按照指定的格式输出到一个字符数组中,同时确保不会发生缓冲区溢出的情况。

在实际编程中,vsnprintf函数可以帮助程序员更加灵活地处理字符串输出,同时提高程序的安全性。

在使用vsnprintf函数时,首先需要了解它的基本语法和用法。

vsnprintf函数通常的形式是:```cint vsnprintf(char *str, size_t size, const char *format, va_list ap);```其中,str是指向输出字符串缓冲区的指针;size是输出字符串的最大长度;format是格式化字符串,用来指定输出的格式;ap是一个指向参数列表的指针。

调用vsnprintf函数后,它会将格式化后的字符串输出到str指向的缓冲区中,最多输出size-1个字符,并在最后自动添加一个空字符'\0',以确保输出的字符串是以null结尾的。

使用vsnprintf函数的一个常见场景是在日志输出中。

我们经常需要将程序执行过程中的一些信息输出到日志文件中,而且需要保证日志信息的格式清晰,并且不会因为数据过长导致缓冲区溢出。

这时候,vsnprintf函数就派上了用场。

通过vsnprintf函数,我们可以将需要输出的信息按照指定的格式写入到一个字符数组中,然后再将这个字符数组写入到日志文件中,从而实现安全可靠的日志输出。

vsnprintf函数还可以用于实现动态生成格式化字符串的功能。

有时候我们需要根据程序运行时的一些变量的值来动态生成输出的格式化字符串,这时候就可以使用vsnprintf函数。

通过将格式化字符串和参数列表分离开来,可以更加灵活地控制输出的格式,同时避免了在程序中硬编码过多的字符串,提高了代码的可读性和可维护性。

printf函数的用法c语言

printf函数的用法c语言

printf函数的用法c语言printf函数是C语言中的输出函数,用于将数据打印到控制台或者指定的输出流中。

printf函数的基本用法是:```c#include <stdio.h>int main() {printf("Hello, World!\n");return 0;}```上述代码会将字符串"Hello, World!"打印到控制台,并在最后添加一个换行符。

printf函数的格式化字符串可以包含转义序列和格式化参数。

转义序列以反斜杠(\)开头,用于表示一些特殊的控制字符。

一些常见的转义序列包括:- \n:换行符- \t:制表符- \\":双引号- \:反斜杠格式化参数用于将变量的值插入到格式化字符串中,以指定的格式进行输出。

常见的格式化参数有:- %d:输出整数- %f:输出浮点数- %c:输出字符- %s:输出字符串例如:```c#include <stdio.h>int main() {int age = 20;float height = 1.75;char name[] = "Alice";printf("My name is %s, I'm %d years old, and my height is %.2f.\n", name, age, height);return 0;}```上述代码会将变量的值插入到格式化字符串中,并以指定的格式进行输出。

输出结果为:```My name is Alice, I'm 20 years old, and my height is 1.75.```。

详解C语言可变参数valist和vsnprintf及printf实现

详解C语言可变参数valist和vsnprintf及printf实现

C语言的变‎长参数在平‎时做开发时‎很少会在自‎己设计的接‎口中用到,但我们最常‎用的接口p‎r intf‎就是使用的‎变长参数接‎口,在感受到p‎r intf‎强大的魅力‎的同时,是否想挖据‎一下到底p‎r intf‎是如何实现‎的呢?这里我们一‎起来挖掘一‎下C语言变‎长参数的奥‎秘。

先考虑这样‎一个问题:如果我们不‎使用C标准‎库(libc)中提供的F‎a cili‎t ies,我们自己是‎否可以实现‎拥有变长参‎数的函数呢‎?我们不妨试‎试。

一步一步进‎入正题,我们先看看‎固定参数列‎表函数,void fixed‎_args‎_func‎(int a, doubl‎e b, char *c){print‎f("a = 0x%p\n", &a);print‎f("b = 0x%p\n", &b);print‎f("c = 0x%p\n", &c);}对于固定参‎数列表的函‎数,每个参数的‎名称、类型都是直‎接可见的,他们的地址‎也都是可以‎直接得到的‎,比如:通过&a我们可以‎得到a的地‎址,并通过函数‎原型声明了‎解到a是i‎n t类型的‎;通过&b我们可以‎得到b的地‎址,并通过函数‎原型声明了‎解到b是d‎o uble‎类型的; 通过&c我们可以‎得到c的地‎址,并通过函数‎原型声明了‎解到c是c‎h ar*类型的。

但是对于变‎长参数的函‎数,我们就没有‎这么顺利了‎。

还好,按照C标准‎的说明,支持变长参‎数的函数在‎原型声明中‎,必须有至少‎一个最左固‎定参数(这一点与传‎统C有区别‎,传统C 允许‎不带任何固‎定参数的纯‎变长参数函‎数),这样我们可‎以得到其中‎固定参数的‎地址,但是依然无‎法从声明中‎得到其他变‎长参数的地‎址,比如:void var_a‎r gs_f‎u nc(const‎char * fmt, ... ){... ...}这里我们只‎能得到fm‎t这固定参‎数的地址,仅从函数原‎型我们是无‎法确定"..."中有几个参‎数、参数都是什‎么类型的,自然也就无‎法确定其位‎置了。

Windows下CC++可变参数宏实现技巧(转)

Windows下CC++可变参数宏实现技巧(转)

Windows下CC++可变参数宏实现技巧(转)在开发过程中,有很多阶段,每个阶段可能会注重不同的重点,我们可能会在不同阶段让程序输出或者打印不同的信息以反应运⾏的情况,所以我们必须分阶段的使得程序输出我们在每个阶段所要关⼼的信息,甚⾄在最后让程序不再输出信息。

这就要⽤到了宏定义!我们知道,在linux下很⽅便的就能实现可变参数宏的定义,⽐如:#define myprint(fmt, a...) printf("%s,%s(),%d:" fmt "/n", __FILE__,__FUNCTION__,__LINE__, ##a)就定义了⾃⼰的输出宏,当不必再输出这些可能是调式,跟踪,断⾔,⽇志...的信息时,可以再定义宏为空:#define myprintf(fmt,a...)这样,重新编译后,这些宏引⽤的地⽅将全部没有语句,从⽽省去这些开销。

但是,在windows下,⼀般我们采⽤的VC6.0,VS2003,VS2005,VS2008(待定)编辑器中⾃带的C/C++编译器并不⽀持变参宏的定义,gcc编译器⽀持,据说最新版本的C99也⽀持。

可以在windows下这样定义宏:#define myprint printf但是,当后期不想再要宏输出了,只能定义 #define myprint为空,在那些有宏调⽤的代码区会留下类似 ("DEBUG:>>%d,%s,%f",idx,"weide001",99.001);这样的语句,它应该会被程序运算⼀次,应该会像函数参数那样被压栈,出栈⼀次,从⽽增加了程序的运⾏开销,不是⼀个上策。

所以,在windows下需要变通⼀下,以下四种⽅式可以作为今后windows下定义可变参宏定义的参考:(1)引⽤系统变参函数:#include <stdarg.h>#ifdef _WIN32#define vsnprinf _vsnprintf#define vsprinf _vsprintf#endifint my_print(const char* file,cosnt char* fun,const char* line,const char *fmt, ...){int t = 0;char out[1024]="";va_list ap;/*Test Env:gcc version 3.4.5 20051201 (Red Hat 3.4.5-2)Result:使⽤vsprintf时:当fmt的长度⼤于1024时出现: 段错误当fmt的长度⼩于1024时出现: 正常使⽤vsnprintf时:当fmt的长度⼤于1024时出现: 多余的字符不保存到out中当fmt的长度⼩于1024时出现: 正常vsnprintf的返回值同snprintf很相似---------------------------------------------------Test Env:Microsoft Windows XP [版本 5.1.2600]Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86Result:使⽤_vsprintf时:当fmt的长度⼤于1024时出现: 段错误当fmt的长度⼩于1024时出现: 正常使⽤_vsnprintf时:当fmt的长度⼤于1024时出现: 多余的字符不保存到out中当fmt的长度⼩于1024时出现: 正常_vsnprintf的返回值同_snprintf很相似*/va_start(ap, fmt);t = vsnprintf(out, 1024, fmt, ap);va_end(ap);printf("%s,%s(),%d: %s/n", file,fun,line,out);return (t);}#define myprint(str) my_print(__FILE__,__FUNCTION__,__LINE__,str)只能输出⼀个字符串参数。

如何把va_list可变参数传送到下一级函数中(如传送到printf)

如何把va_list可变参数传送到下一级函数中(如传送到printf)

如何把va_list可变参数传送到下⼀级函数中(如传送到printf)最近我在⼀个LCD上想实现打印格式化字符串的功能,实现这样的功能可有两种⽅式:⼀最直接的就是⾃⼰去解析类似于printf功能的⼀个函数;⼆⽐较简单的⽅法是使⽤已有的sprintf功能,把格式化字符串打印到⼀个字符缓冲区中,再将这个字符缓冲区打印到LCD上来。

这⾥选择了第⼆种⽅法!我已经把这个嵌⼊式程序弄到pc机上来运⾏了,第⼀次编写的代码是这样⼦的:1 #include <stdio.h>2 #include <stdarg.h>34void lcm_appendf(const char *fmt, ...)5 {6char fm_buffer[128];7int fm_len = 0;8 fm_len = snprintf(fm_buffer, 128, fmt);910 printf("fm_len = %d\r\n", fm_len);11 printf("%s", fm_buffer);12 }1314int main(int argc, char **args)15 {16char c;1718// printf("Hello, this is Merlin Dec:%d, Hex:0x%x, Str:%s\r\n", 254, 0x32, "tfAna");19 lcm_appendf("Hello, this is Merlin Dec:%d, Hex:%x, Str:%s\r\n", 254, 0x32, "tfAna");20 scanf("%c", &c);21 }编译时提⽰错误:$ gcc lcm_appendf.clcm_appendf.c: In function ‘lcm_appendf’:lcm_appendf.c:8:2: warning: format not a string literal and no format arguments [-Wformat-security]lcm_appendf.c:8:2: warning: format not a string literal and no format arguments [-Wformat-security]表⽰没有格式参数!原来我忘记把格式(%d%x%s)对应的参数(254 0x32 "tfAna")写上去。

c语言变量参数va_list和_ vsnprintfprintf实现的详细说明.doc

c语言变量参数va_list和_ vsnprintfprintf实现的详细说明.doc

c语言变量参数va_list和_ vsnprintfprintf实现的详细说明在平时开发时,我们自己设计的接口很少使用-C语言的变长参数,但是最常用的接口是变长参数接口。

在感受printf强大魅力的同时,您想知道printf是如何实现的吗?在这里,让我们探索C语言中可变长度参数的奥秘。

首先考虑这样一个问题:如果我们不使用C标准库(libc)中提供的工具,我们能自己用可变长度参数实现函数吗?我们不妨试试。

一步一步地进入正题,让我们看看固定参数列表函数void fixed _ args _ func (inta,double b,char * c) {printf ('a=0x% p \ n ',a);printf('b=0x%p\n ',b);printf('c=0x%p\n ',c);对于具有固定参数列表的函数,每个参数的名称和类型是直接可见的,它们的地址也是直接可用的,例如:通过函数原型声明,我们可以得到A到A的地址,并知道A是int类型的。

通过函数原型声明,我们可以得到B到B的地址,并知道B是双类型的。

通过C我们可以得到C的地址,通过函数原型声明我们知道C是char*类型。

但是对于具有可变长度参数的函数,我们就不那么平滑了。

幸运的是,根据C标准的描述,支持可变长度参数的函数在原型声明中必须至少有一个最左边的固定参数(这不同于传统的C,它允许没有任何固定参数的纯可变长度参数函数),所以我们可以得到固定参数的地址,但是我们仍然不能从声明中得到其他可变长度参数的地址,例如:V oidwar _ args _ func(常量* fmt,){.}这里我们只能得到固定参数fmt的地址。

我们无法确定几个参数的类型和' .'中的参数仅仅从功能原型,我们自然无法确定它们的位置。

那么如何才能做到呢?回想一下函数参数转移的过程。

不管' .'中有多少参数以及每个参数是什么类型,它们与固定参数的参数传递过程相同。

va_list、va_start和va_end使用

va_list、va_start和va_end使用

va_list、va_start和va_end使⽤我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,由于1、硬件平台的不同 2、编译器的不同,所以定义的宏也有所不同。

在ANSI C中,这些宏的定义位于stdarg.h中,典型的实现如下:typedef char *va_list;va_start宏,获取可变参数列表的第⼀个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数):#define va_start(list,param1) ( list = (va_list)&param1+ sizeof(param1) )va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下⼀参数(mode参数描述了当前参数的类型):#define va_arg(list,mode) ( (mode *) ( list += sizeof(mode) ) )[-1]va_end宏,清空va_list可变参数列表:#define va_end(list) ( list = (va_list)0 )注:以上sizeof()只是为了说明⼯作原理,实际实现中,增加的字节数需保证为为int的整数倍如:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )为了理解这些宏的作⽤,我们必须先搞清楚:C语⾔中函数参数的内存布局。

⾸先,函数参数是存储在栈中的,函数参数从右往左依次⼊栈。

以下⾯函数为讨论对象:void test(char *para1,char *param2,char *param3, char *param4){va_list list;......return;}在linux中,栈由⾼地址往低地址⽣长,调⽤test函数时,其参数⼊栈情况如下:当调⽤va_start(list,param1) 时:list指针指向情况对应下图:最复杂的宏是va_arg。

va_arg用法

va_arg用法

va_arg用法va_arg是C语言中的一个宏,用于在可变参数列表中访问可变数量的参数。

它允许程序员使用va_list、va_start、va_arg、va_end 等宏来处理可变参数列表,从而方便地处理格式化输入输出、错误处理等场景。

一、基本用法va_arg是宏定义的,用于访问va_list列表中的下一个参数。

它通常与printf函数一起使用,用于格式化输出。

在使用va_arg时,需要指定要访问的参数类型,以便正确地读取和存储参数的值。

以下是一个简单的示例代码,展示了va_arg的基本用法:```c#include <stdarg.h>#include <stdio.h>int main() {int x = 10;float y = 3.14;char c = 'A';va_list args;va_start(args, x); // 初始化va_list列表while (x != 0) { // 循环访问每个参数switch (x) {case sizeof(int):printf("The type of int is %s.\n",va_type(args)); // 输出int类型printf("The value of int is %d.\n",va_arg(args, int)); // 输出int值break;case sizeof(float):printf("The type of float is %s.\n",va_type(args)); // 输出float类型printf("The value of float is %f.\n", va_arg(args, float)); // 输出float值break;case sizeof(char):printf("The type of char is %s.\n",va_type(args)); // 输出char类型printf("The value of char is %c.\n",va_arg(args, char)); // 输出char值break;default:printf("Unexpected type size.\n"); // 其他类型大小不匹配时输出此消息break;}x--; // 继续下一个参数}va_end(args); // 清理va_list列表return 0;}```在上面的示例代码中,我们使用va_start宏初始化va_list列表,并使用va_arg宏逐个访问参数的值。

C语言Printf之使用及在单片机中的用法

C语言Printf之使用及在单片机中的用法

一、printf常用说明printf的格式控制的完整格式:% - 0 m.n l或h 格式字符下面对组成格式说明的各项加以说明:①%:表示格式说明的起始符号,不可缺少。

②-:有-表示左对齐输出,如省略表示右对齐输出。

③0:有0表示指定空位填0,如省略表示指定空位不填。

④m.n:m指域宽,即对应的输出项在输出设备上所占的字符数。

N指精度。

用于说明输出的实型数的小数位数。

为指定n时,隐含的精度为n=6位。

⑤l或h:l对整型指long型,对实型指double型。

h用于将整型的格式字符修正为short型。

----------------------------------格式字符格式字符用以指定输出项的数据类型和输出格式。

①d格式:用来输出十进制整数。

有以下几种用法:%d:按整型数据的实际长度输出。

%md:m为指定的输出字段的宽度。

如果数据的位数小于m,则左端补以空格,若大于m,则按实际位数输出。

%ld:输出长整型数据。

②o格式:以无符号八进制形式输出整数。

对长整型可以用"%lo"格式输出。

同样也可以指定字段宽度用“%mo”格式输出。

例:main(){ int a = -1;printf("%d, %o", a, a);}运行结果:-1,177777程序解析:-1在内存单元中(以补码形式存放)为(1111111111111111)2,转换为八进制数为(177777)8。

③x格式:以无符号十六进制形式输出整数。

对长整型可以用"%lx"格式输出。

同样也可以指定字段宽度用"%mx"格式输出。

④u格式:以无符号十进制形式输出整数。

对长整型可以用"%lu"格式输出。

同样也可以指定字段宽度用“%mu”格式输出。

⑤c格式:输出一个字符。

⑥s格式:用来输出一个串。

有几中用法%s:例如:printf("%s", "CHINA")输出"CHINA"字符串(不包括双引号)。

详解 C语言可变参数 va_list和_vsnprintf及printf实现

详解 C语言可变参数 va_list和_vsnprintf及printf实现

C语言的变长参数在平时做开发时很少会在自己设计的接口中用到,但我们最常用的接口printf就是使用的变长参数接口,在感受到printf强大的魅力的同时,是否想挖据一下到底printf是如何实现的呢?这里我们一起来挖掘一下C语言变长参数的奥秘。

先考虑这样一个问题:如果我们不使用C标准库(libc)中提供的Facilities,我们自己是否可以实现拥有变长参数的函数呢?我们不妨试试。

一步一步进入正题,我们先看看固定参数列表函数,void fixed_args_func(int a, double b, char *c){printf("a = 0x%p\n", &a);printf("b = 0x%p\n", &b);printf("c = 0x%p\n", &c);}对于固定参数列表的函数,每个参数的名称、类型都是直接可见的,他们的地址也都是可以直接得到的,比如:通过&a我们可以得到a的地址,并通过函数原型声明了解到a是int类型的; 通过&b我们可以得到b的地址,并通过函数原型声明了解到b是double类型的; 通过&c我们可以得到c的地址,并通过函数原型声明了解到c是char*类型的。

但是对于变长参数的函数,我们就没有这么顺利了。

还好,按照C标准的说明,支持变长参数的函数在原型声明中,必须有至少一个最左固定参数(这一点与传统C有区别,传统C 允许不带任何固定参数的纯变长参数函数),这样我们可以得到其中固定参数的地址,但是依然无法从声明中得到其他变长参数的地址,比如:void var_args_func(const char * fmt, ... ){... ...}这里我们只能得到fmt这固定参数的地址,仅从函数原型我们是无法确定"..."中有几个参数、参数都是什么类型的,自然也就无法确定其位置了。

c语言可变参数函数

c语言可变参数函数

c语言可变参数函数C语言的可变参数函数(Variadic Function)是一种特殊的函数,可以接受不定数量的参数。

在C语言中,可变参数函数通常使用stdarg.h头文件中的宏来实现。

可变参数函数的基本原理是使用一个参数列表来接受可变数量的参数,通过宏来提取参数列表中的每个参数的值。

在了解可变参数函数之前,我们先来看一个简单的例子:```c#include <stdio.h>#include <stdarg.h>double average(int count, ...)va_list args;double sum = 0;int i;va_start(args, count);for (i = 0; i < count; i++)sum += va_arg(args, int);}va_end(args);return sum / count;int maidouble avg = average(3, 1, 2, 3);printf("平均值为: %lf\n", avg);return 0;```在上面的代码中,average函数的第一个参数是固定的,用于指定后续参数的数量。

使用va_list类型的args变量来存储参数列表,va_start宏用于初始化args变量,va_end宏用于结束参数列表的获取。

在for循环中,使用va_arg宏来获取每个参数的值。

va_arg宏的第一个参数是va_list类型的变量,用于指定参数列表,第二个参数是可变参数的类型。

在本例中,参数的类型为int。

除了上面的例子,C语言中还有其他一些常见的可变参数函数,比如printf函数就是一个典型的可变参数函数。

```c#include <stdio.h>#include <stdarg.h>void my_printf(const char* format, ...)va_list args;va_start(args, format);vprintf(format, args);va_end(args);int maimy_printf("Hello, %s! You are %d years old.\n", "John", 25);return 0;```在上面的例子中,my_printf函数模拟了printf函数的功能,可以接受任意数量的参数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言的变长参数在平时做开发时很少会在自己设计的接口中用到,但我们最常用的接口printf就是使用的变长参数接口,在感受到printf强大的魅力的同时,是否想挖据一下到底printf是如何实现的呢这里我们一起来挖掘一下C语言变长参数的奥秘。

先考虑这样一个问题:如果我们不使用C标准库(libc)中提供的Facilities,我们自己是否可以实现拥有变长参数的函数呢我们不妨试试。

一步一步进入正题,我们先看看固定参数列表函数,void fixed_args_func(int a, double b, char *c){printf("a = 0x%p\n", &a);printf("b = 0x%p\n", &b);printf("c = 0x%p\n", &c);}对于固定参数列表的函数,每个参数的名称、类型都是直接可见的,他们的地址也都是可以直接得到的,比如:通过&a我们可以得到a的地址,并通过函数原型声明了解到a是int 类型的; 通过&b我们可以得到b的地址,并通过函数原型声明了解到b是double类型的; 通过&c我们可以得到c的地址,并通过函数原型声明了解到c是char*类型的。

但是对于变长参数的函数,我们就没有这么顺利了。

还好,按照C标准的说明,支持变长参数的函数在原型声明中,必须有至少一个最左固定参数(这一点与传统C有区别,传统C允许不带任何固定参数的纯变长参数函数),这样我们可以得到其中固定参数的地址,但是依然无法从声明中得到其他变长参数的地址,比如:void var_args_func(const char * fmt, ... ){... ...}这里我们只能得到fmt这固定参数的地址,仅从函数原型我们是无法确定"..."中有几个参数、参数都是什么类型的,自然也就无法确定其位置了。

那么如何可以做到呢在大脑中回想一下函数传参的过程,无论"..."中有多少个参数、每个参数是什么类型的,它们都和固定参数的传参过程是一样的,简单来讲都是栈操作,而栈这个东西对我们是开放的。

这样一来,一旦我们知道某函数帧的栈上的一个固定参数的位置,我们完全有可能推导出其他变长参数的位置,顺着这个思路,我们继续往下走,通过一个例子来诠释一下:(这里要说明的是:函数参数进栈以及参数空间地址分配都是"实现相关"的,不同平台、不同编译器都可能不同,所以下面的例子仅在IA-32,Windows XP, MinGW gcc v3.4.2下成立)我们先用上面的那个fixed_args_func函数确定一下这个平台下的入栈顺序。

int main(){fixed_args_func(17, , "hello world");return 0;}a = 0x0022FF50b = 0x0022FF54c = 0x0022FF5C从这个结果来看,显然参数是从右到左,逐一压入栈中的(栈的延伸方向是从高地址到低地址,栈底的占领着最高内存地址,先入栈的参数,其地理位置也就最高了)。

我们基本可以得出这样一个结论:= + x_sizeof(b); /*注意: x_sizeof != sizeof,后话再说 */= + x_sizeof(a);有了以上的"等式",我们似乎可以推导出 void var_args_func(const char * fmt, ... ) 函数中,可变参数的位置了。

起码第一个可变参数的位置应该是: = + x_sizeof(fmt); 根据这一结论我们试着实现一个支持可变参数的函数:void var_args_func(const char * fmt, ... ){char *ap;ap = ((char*)&fmt) + sizeof(fmt);printf("%d\n", *(int*)ap);ap = ap + sizeof(int);printf("%d\n", *(int*)ap);ap = ap + sizeof(int);printf("%s\n", *((char**)ap));}int main(){var_args_func("%d %d %s\n", 4, 5, "hello world");}输出结果:45hello worldvar_args_func只是为了演示,并未根据fmt消息中的格式字符串来判断变参的个数和类型,而是直接在实现中写死了,如果你把这个程序拿到solaris 9下,运行后,一定得不到正确的结果,为什么呢,后续再说。

先来解释一下这个程序。

我们用ap获取第一个变参的地址,我们知道第一个变参是4,一个int型,所以我们用(int*)ap以告诉编译器,以ap为首地址的那块内存我们要将之视为一个整型来使用,*(int*)ap获得该参数的值;接下来的变参是5,又一个int型,其地址是ap + sizeof(第一个变参),也就是ap + sizeof(int),同样我们使用*(int*)ap获得该参数的值;最后的一个参数是一个字符串,也就是char*,与前两个int型参数不同的是,经过ap + sizeof(int)后,ap指向栈上一个char*类型的内存块(我们暂且称之tmp_ptr, char *tmp_ptr)的首地址,即ap -> &tmp_ptr,而我们要输出的不是printf("%s\n", ap),而是printf("%s\n", tmp_ptr); printf("%s\n", ap)是意图将ap所指的内存块作为字符串输出了,但是ap -> &tmp_ptr,tmp_ptr所占据的4个字节显然不是字符串,而是一个地址。

如何让&tmp_ptr是char **类型的,我们将ap进行强制转换(char**)ap <=> &tmp_ptr,这样我们访问tmp_ptr只需要在(char**)ap前面加上一个*即可,即printf("%s\n", *(char**)ap);前面说过,如果将var_args_func放到solaris上,一定是得不到正确结果的为什么呢由于内存对齐。

编译器在栈上压入参数时,不是一个紧挨着另一个的,编译器会根据变参的类型将其放到满足类型对齐的地址上的,这样栈上参数之间实际上可能会是有空隙的。

上述例子中,我是根据反编译后的汇编码得到的参数间隔,还好都是4,然后在代码中写死了。

为了满足代码的可移植性,C标准库在中提供了诸多Facilities以供实现变长长度参数时使用。

这里也列出一个简单的例子,看看利用标准库是如何支持变长参数的:#include <>void std_vararg_func(const char *fmt, ... ) {va_list ap;va_start(ap, fmt);printf("%d\n", va_arg(ap, int));printf("%f\n", va_arg(ap, double));printf("%s\n", va_arg(ap, char*));va_end(ap);}int main() {std_vararg_func("%d %f %s\n", 4, , "hello world");}输出:4hello world对比一下 std_vararg_func和var_args_func的实现,va_list似乎就是char*, va_start 似乎就是 ((char*)&fmt) + sizeof(fmt),va_arg似乎就是得到下一个参数的首地址。

没错,多数平台下中va_list, va_start和var_arg的实现就是类似这样的。

一般会包含很多宏,看起来比较复杂。

在有的系统中的实现依赖some special functions built into the the compilation system to handle variable argument lists and stack allocations,多数其他系统的实现与下面很相似:(Visual C++ 的实现较为清晰,因为windows上的应用程序只需要在windows平台间做移植即可,没有必要考虑太多的平台情况)。

C语言va_list与_vsnprintf的使用先举一个例子:#define bufsize 80char buffer[bufsize];/* 这个函数用来格式化带参数的字符串*/int vspf(char *fmt, ...){va_list argptr;写可变参数的C函数要在程序中用到以下这些宏:使用可变参数应该有以下步骤:1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针.2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数.3)然后用va_arg返回可变的参数,并赋值给整数j. va_arg的第二个参数是你要返回的参数的类型,这里是int型.4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使用第二个参数了.如果函数有多个可变参数的,依次调用va_arg获取各个参数.如果我们用下面三种方法调用的话,都是合法的,但结果却不一样:可变参数在编译器中的处理我们知道va_start,va_arg,va_end是在中被定义成宏的,由于:1)硬件平台的不同2)编译器的不同Microsoft Visual Studio\VC98\Include\中,typedef char * va_list;/*把va_list被定义成char*,这是因为在我们目前所用的PC机上,字符指针类型可以用来存储内存单元地址。

而在有的机器上va_list是被定义成void*的*/#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) /*_INTSIZEOF (n)宏是为了考虑那些内存地址需要对齐的系统,从宏的名字来应该是跟sizeof(int)对齐。

相关文档
最新文档