C语言println函数

发现很多现代的语言中都有println这个函数,用起来很是方便,不用每次打印都要加上"\n",自己也实现了一个,方便平时调试的时候用。

 
 
  1. #include <stdarg.h>
  2. int println(const char *fmt, ...)
  3. {
  4. char printf_buf[1024];
  5. va_list args;
  6. int printed;
  7. va_start(args, fmt);
  8. printed = vsprintf(printf_buf, fmt, args);
  9. va_end(args);
  10. puts(printf_buf);
  11. return printed;
  12. }

这里用到了C语言的可变参函数,就顺便谈谈C语言的可变参函数吧。所谓可变参函数即函数的参数可以是不定个数。上面我们已经看到了变参函数的定义方法,用形如int println(const char *fmt, ...)来定义可变参函数。

注意:上例中的第一个参数fmt是不可省略的,可变参函数至少需要一个普通的形参。


C语言之所以支持可变参函数,一个重要的原因是C调用规范中规定了C语言函数调用时,参数入栈的书序是从右往左,这意味着,栈顶的参数是第一个参数。这样,被调用的函数,就不需要关心调用者会传递几个参数进来,只要关心自己用到几个参数既可以了。

例如这样一个调用
142141529669471.png
查看函数的汇编代码
142141538579844.png
可以看到,对println("%d %d", 10, 20, 30, 40);的调用确实是从右往左将参数压入到栈中。


这里还有另外一个问题是:因为可变参函数,函数定义的时候并没有定义形参原型,调用的时候怎么使用参数呢?为此,C语言定义了如下的宏:

 
 
  1. void va_start(va_list ap, last);//取第一个可变参数(如上述printf中的i)的指针给ap,last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);
  2. type va_arg(va_list ap, type);//返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;type表示当前可变参数的类型(支持的类型位int和double);
  3. void va_end(va_list ap);//将ap置为NULL

其在头文件中的定义如下:

 
 
  1. /*
  2. * define a macro to compute the size of a type, variable or expression,
  3. * rounded up to the nearest multiple of sizeof(int). This number is its
  4. * size as function argument (Intel architecture). Note that the macro
  5. * depends on sizeof(int) being a power of 2!
  6. */
  7. #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
  8. #define _VA_LIST char*
  9. typedef _VA_LIST va_list;
  10. #define va_dcl va_list va_alist;
  11. #define va_start(ap) ap = (va_list)&va_alist
  12. #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  13. #define va_end(ap) ap = (va_list)0

从上面的定义很容易可以看出,va_start使ap指向第一个可选参数。va_arg返回参数列表中的当前参数并使ap指向参数列表中的下一个参数。va_end则将ap置为空指针。
关于_INTSIZEOF做一点简单的解释:因为sizeof(int)2^n,因此它的位模式必然是1...000,因此该宏会





转载于:https://www.cnblogs.com/joyzhuang/p/4025270.html

### C语言中的 `printf` 和 `println` 函数 #### `printf` 函数 `printf` 是 C 语言中用于格式化输出的标准库函数之一。此函数允许向标准输出设备(通常是终端)发送格式化的字符串和其他数据类型[^1]。 - **功能特性** - 支持多种格式说明符来控制不同类型的数据如何被转换成字符串并输出。 - `%d` 或 `%i`: 输出十进制整数。 - `%f`: 浮点数。 - `%s`: 字符串。 - 更多其他类型的格式符也受支持。 - **返回值**: 成功时返回写入的字符数量,失败则返回负值。 ```c #include <stdio.h> int main(void){ int num = 42; float pi = 3.14159; printf("The number is %d and Pi value is %.2f.\n",num,pi); } ``` #### `println` 函数 需要注意的是,在纯正的 ANSI C 中并没有内置名为 `println` 的函数。然而,在某些特定环境或编程框架下可能会存在这样的自定义实现方式,比如 Java 中有类似的 `System.out.println()` 方法用来自动添加新行结束标记到输出内容后面[^2]。 如果是在讨论类似于 Shell 脚本里的命令,则确实有一个叫作 `print` 和 `println` 的区别在于后者会在每次调用后附加一个换行符。但在严格意义下的 C 编程环境中谈论 `println` 并不合适,因为这不是标准的一部分。 对于希望在每条消息之后都加上换行效果的情况,可以直接通过给定 `\n` 来达到目的: ```c printf("This message ends with a newline character.\n"); ``` 或者创建自己的宏定义简化操作: ```c #define PRINTLN(x) (void)(printf((x), "\n")) ... PRINTLN("A simple line of text."); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值