printf()中%n格式说明符

一 遇到%n

昨天在写scanf 的输入异常处理时遇到了一个从未见过的格式说明符:%n

sscanf(str, "%d %n", &v, &c)

从运行结果来看,c的值是str的长度。


二 Stack Overflow 上关于%n 的QA

于是我在stack overflow上找到了关于这个格式说明符的QA。
What is the use of the %n format specifier in C?

第一个回答是:

Nothing printed. The argument must be a pointer to a signed int, where the number of characters written so far is stored.

意思是,不会打印任何东西。 这个参数必须是一个有符号整数的指针,它存储它出现之前打印的所有字符数。

并给了一个例子:

#include <stdio.h>

int main()
{
  int val;

  printf("blah %n blah\n", &val);

  printf("val = %d\n", val);

  return 0;

}

结果是:

blah  blah
val = 5

第二个答案给了另一个例子:

int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");

结果是:

hello: Foo
       Bar

三 我的运行异常和调试情况

我决定手动运行一下。

我的程序如下:

#include <stdio.h>

int main(void) 
{
    /* test 1*/
    int val;
    printf("blah %n blah\n", &val);
    printf("val = %d\n", val);

    /* test 2*/
    int n;
    printf("%s: %nFoo\n", "hello", &n);
    printf("%*sBar\n", n, "");

    return 0;
}

我先用MinGW的gcc进行编译运行:

gcc -g %n.c -o %n

结果运行时,一直在打印空格,控制台旁边的滑块迅速向下滑行,过了好一会才有字符出现。

我试着用gdb进行调试:

7               printf("blah %n blah\n", &val);
(gdb) p val
$1 = 4194432
(gdb) n
warning: Invalid parameter passed to C runtime function.

blah 8          printf("val = %d\n", val);
(gdb) p val
$2 = 4194432

发现声明变量时和运行printf("blah %n blah\n", &val) 后,val的值并没有发生改变,而且抛出了一个warning:Invalid parameter passed to C runtime function. 对于test 2也是同样的情况。

接着我试着用Developer Command Prompt for VS 2017对该程序进行编译运行:

cl %n.c
用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.10.25019 版
版权所有(C) Microsoft Corporation。保留所有权利。

%n.c
Microsoft (R) Incremental Linker Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:%n.exe
%n.obj

运行:%n ,结果:
停止工作


四 用在线IDE进行测试

为什么我这里运行异常呢?

我另外找了两个在线IDE测试。以下是截图:

1、http://ide.geeksforgeeks.org/

Web IDE test1

2、http://codepad.org
Web IDE test2

结果都是正常。


五 如何解决“Invalid parameter passed to C runtime function”?

最后我的注意力转移到如何解决“ Invalid parameter passed to C runtime function.”这个问题上来了。

于是,我又跑到Stack Overflow上寻找答案了。how-to-debug-invalid-parameter-passed-to-c-runtime-function

第一个答案建议用gcc 配合选项进行设置调试命令。我试了一个用c99标准和c11标准,竟然都可以成功运行!

gcc -g %n.c -o %n_c99 -std=c99
%n_c99

blah  blah
val = 5
hello: Foo
       Bar

gcc -g %n.c -o %n_c11 -std=c11
%n_c11

blah  blah
val = 5
hello: Foo
       Bar

但是单纯的不加选项,就不能成功运行。

接着我找到了:warning-invalid-parameter-passed-to-c

按照里面的方式,我设置了断点并run:

(gdb) b OutputDebugStringA
(gdb) r
Starting program: C:\Users\\Desktop/%n_.exe
[New Thread 2748.0x26d8]
[New Thread 2748.0x167c]

Breakpoint 1, 0x773cb540 in OutputDebugStringA () from C:\WINDOWS\SysWOW64\KernelBase.dll
(gdb) bt
#0  0x773cb540 in OutputDebugStringA () from C:\WINDOWS\SysWOW64\KernelBase.dll
#1  0x7634811f in msvcrt!_invalid_parameter () from C:\WINDOWS\SysWOW64\msvcrt.dll
#2  0x762f5a40 in wctype () from C:\WINDOWS\SysWOW64\msvcrt.dll
#3  0x00010001 in ?? ()
#4  0x7636a9b7 in vswprintf () from C:\WINDOWS\SysWOW64\msvcrt.dll
#5  0x7636419b in printf () from C:\WINDOWS\SysWOW64\msvcrt.dll
#6  0x763a2628 in msvcrt!_iob () from C:\WINDOWS\SysWOW64\msvcrt.dll
#7  0x00405064 in __register_frame_info ()
#8  0x00401482 in main () at %n.c:7

看来问题比想象中复杂。我的初步猜想是Window环境下C语言在某些版本中,不允许 在printf中使用%n对于有符号整数的赋值。把这个问题放在这里,希望以后随着能力的增长,能够解决。

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值