printf("%*d",5,10);这个表达式正确?如果正确输出什么?怎么实现的?

本文深入解析了C语言中printf函数中*参数的使用方式,通过实例展示了如何控制输出前导空格数量,理解其背后的实现原理。

The width and precision formatting parameters may be omitted, or they can be a fixed number embedded in the format string, or passed as another function argument when indicated by an asterisk "*" in the format string. For example printf("%*d", 5, 10) will result in "   10" being printed, with a total width of 5 characters, and printf("%.*s", 3, "abcdef") will result in "abc" being printed.

----------------------------------以上内容是11月21日更新,来自wikipedia------------------------------------------------------------

今天遇到一个从来没有遇到过的很神奇的表达式——

printf("%*d",5,10);


printf("%d",10);这谁都知道,打印整形数据10,完事,但是。。。但是如果%后面跟了个*捏?而且有对应的参数是个神马情况捏?


事实是这里的*对应的参数,也就是例子里面的5,控制数字前输出的空格!

神奇吧,自己试试printf("%*d",5,10);这个语句


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


下面请允许我自恋的扮演一下福尔摩斯,找出真相。。。

首先找到,printf的实现代码,GCC里面printf是个壳,也就是说他是利用别人的功能实现的,而这里的”别人“其实就是真正实现数据输出的是下面这个东西

。。。。

_doprnt (const char *format, va_list ap, FILE *stream)
{
  const char * ptr = format;
  char specifier[128];//格式化输出的那个常量字符串的缓冲区,很关键的一个东东
  int total_printed = 0;
  
  while (*ptr != '\0')
    {
      if (*ptr != '%') /* While we have regular characters, print them.  */
PRINT_CHAR(*ptr);
      else /* We got a format specifier! */当”扫描"到%的时候,就说明要发生格式化输出了,并且%之后的那个格式说明符就是该数据的读取格式
{
 char * sptr = specifier;//指针sptr指向那个缓冲区
 int wide_width = 0, short_width = 0;
 
 *sptr++ = *ptr++; /* Copy the % and move forward.  */把%保存到格式化输出的那个缓冲区


 while (strchr ("-+ #0", *ptr)) /* Move past flags.  */读者可以无视这个,和本主题无关
   *sptr++ = *ptr++;


 if (*ptr == '*')关键的到了!如果那个printf里面那个常量字符串里%后面跟了个*就执行 COPY_VA_INT;这里是个宏定义,我们来看看宏定义是什么
   COPY_VA_INT;


 

------------------------------------------------------------------------------------------------------------------------------------

#define COPY_VA_INT

do { \
const int value = abs (va_arg (ap, int)); \ 取变长参数列表里那个对应的那个参数,此处是5,然后赋值给变量value
char buf[32]; \ 一个新的缓冲区
ptr++; /* Go past the asterisk.  */ \  指向printf常量字符串的下一个位置,这个和主题关系不大,和谐掉
*sptr = '\0'; /* NULL terminate sptr.  */ \ 把指向specifier 缓冲区当前位置的指针指向一个空字符
sprintf(buf, "%d", value); \把value的值写到buf缓冲区里面
strcat(sptr, buf); \把buf缓冲区的内容“衔接”到sptr的后面!事情就发生变化了,格式化输出的格式说明符%之后就变成 %5d!!!!所以会有空格输出
while (*sptr) sptr++; \
     } while (0)




------------------------------------------------------------------------------------------------------------------------------------

这里sptr是指向specifier缓冲区的,真正按格式化打印数据是按照specifier缓冲区里的字符串格式来打印的,所以如果你没看懂,可以简单的理解成*被替换成printf("%*d",number,var);中的number,然后按照printf("%number d"10);来格式化输出数据









  





                
<think> 我们已知用户的问题:在printf函数中使用%d格式说明符打印两个整数的方法 根据引用[1]和[2],我们知道printf可以使用格式说明符(如%d)来输出整数,并且可以同时输出多个变量。 方法:在格式控制字符串中使用两个%d,然后在输出参数列表中按顺序提供两个整数变量(或常量)。 例如:printf("第一个数:%d,第二个数:%d", num1, num2); 注意:格式说明符的数量和类型必须与后面的参数一一对应,否则会出现错误(如引用[3]中提到的类型不匹配或参数数量不匹配问题)。 下面我们详细说明: 1. 格式控制字符串中包含两个%d,分别对应后面的两个整数参数。 2. 第一个%d对应第一个整数参数,第二个%d对应第二个整数参数。 3. 可以在格式控制字符串中添加任意文本,使输出更易读。 示例代码: 我们参考引用[1]的代码风格,写一个示例: </think> ### 在printf函数中使用%d格式说明符打印两个整数的方法 #### 1. **基础语法格式** 使用两个`%d`格式说明符配合两个整型变量: ```c int num1 = 42; int num2 = 99; printf("数值1 = %d, 数值2 = %d", num1, num2); ``` - ✅ **输出效果**:`数值1 = 42, 数值2 = 99` - 🔄 **位置对应**:第一个`%d`对应`num1`,第二个`%d`对应`num2` - ⚠️ **注意事项**: - 格式说明符数量必须与参数数量严格匹配 - 类型必须一致(均为整型) #### 2. **参数顺序原理(内存操作)** 参数按**从右向左**顺序压栈: ```c printf("A:%d B:%d", a, b); ``` 执行过程: ```mermaid sequenceDiagram main->>+printf: 压栈 b的值 main->>+printf: 压栈 a的值 main->>printf: 压栈 格式字符串地址 printf->>printf: 解析格式串 printf-->>-main: 输出"A:avalue B:bvalue" ``` 📌 关键:格式字符串中的`%d`按 **从左到右** 顺序匹配栈中的参数(栈顶参数对应第一个`%d`) #### 3. **格式化进阶技巧** ```c // 对齐与填充 printf("|%-8d|%08d|", 123, 456); // 输出:|123 |00000456| // 表达式作为参数 printf("乘积:%d", num1 * num2); // 直接计算输出 // 八进制/十六进制混合输出 printf("十进制:%d, 十六进制:0x%x", 255, 255); // 输出:十进制:255, 十六进制:0xff ``` #### 4. **类型安全与常见错误** 引用[3]案例警示: ```c double d = 3.14; printf("错误示例:%d %d", d); // 错误1:类型不匹配 错误2:参数不足 ``` - 💥 **风险分析**: 1. 用`%d`输出非整型数据导致未定义行为 2. 参数数量不足会导致读取无效内存 3. 顺序错乱:`printf("%d %d", b, a)`输出$a$和$b$的值但标签相反 #### 5. 完整验证示例 ```c #include <stdio.h> int main() { int score = 95, count = 30; // 正确使用双%d printf("平均分:%d, 人数:%d\n", score, count); // 带格式控制 printf("十六进制:0x%X, 带符号:%+d", -1, 100); return 0; } ``` **输出**: ``` 平均分:95, 人数:30 十六进制:0xFFFFFFFF, 带符号:+100 ``` > 关键点:双`%d`输出本质是 **格式字符串解析+栈内存参数读取** 的协同过程,必须保证类型匹配和数量一致[^1][^3]。 --- ### 相关问题 1. 当使用`printf("%d %d", 3.14)`时实际会发生什么? 2. 如何用单个`printf`输出三个不同类型的变量(int, float, char)? 3. `printf`的格式说明符(如`%8d`)如何影响程序的内存访问? 4. 在嵌入式系统中使用多个`%d`是否有特殊注意事项? 5. 为什么`printf("%d %d", a, b)`中参数要从右向左压栈?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值