【C】C语言printf,格式化字符串,缓冲区

C语言printf,格式化字符串,缓冲区


前言

用惯了 Python 字符串的 format,感觉 C 的 printf 用起来好别扭,于是写这篇来帮忙记忆一些细节。

然后这是cpp官方文档 (C和C++的printf是一样的)

http://www.cplusplus.com/reference/cstdio/printf/

格式化字符串

printf 常用的format标签:

这里用了为了方便,用了宏函数(不过宏函数是不能滥用的)。

关于宏函数的一些特殊用法,可参考这篇博客:

https://blog.csdn.net/q2519008/article/details/80934815

顺带一提,我用 VSCODE 写C或C++代码时,宏函数也有高亮,很方便。

#include <stdio.h>
#include <stdbool.h>
#include <complex.h>

// 下面这是一个用于输出结果的宏函数
// ... 表示任意数量参数,对应后面的 __VA_ARGS__
// #A 表示把A字符串化,这对__VA_ARGS__也一样
// ##A 表示把A与前面的进行拼接,但是##__VA_ARGS__行为不太一样
// ##__VA_ARGS__ 表示:当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错
// 关于如何把 FORMAT 参数嵌入字符串里,这了用上了字符串拼接的写法,即形如"xx""xx"的写法

#define PRINTF(FORMAT,...) printf("(%s) ---> ("FORMAT")\n",#__VA_ARGS__,##__VA_ARGS__);

int main(){
    int intNum = 3;
    long longNum = 3L;
    long long LLNum = 3LL;
    short ShortNum = 3;
    char c='3';
    unsigned short UShortNum = 3U;
    unsigned int UIntNum = 3U;
    unsigned long long ULLNum = 3ULL;
    float FloatNum = 3.0f;
    double DoubleNum = 3.0;
    long double LDNum = 3.0;

    //C99新类型
    _Bool boolVar = true; // 注意,这里的 true 只是一个宏而已(int的1),和C++的true是不同的
    long double _Complex LDComplexNum = 3.0+3.0I;// 或者 3+3*I,I是complex.h里的宏 
    
    PRINTF("%d",intNum); // 还有一种 %i 的写法,但我没怎么用过
    PRINTF("%ld",longNum);
    PRINTF("%lld",LLNum);
    PRINTF("%hd",ShortNum);
    PRINTF("%c",c);
    PRINTF("%hu",UShortNum);
    PRINTF("%u",UIntNum);
    PRINTF("%llu",ULLNum);
    PRINTF("%f",FloatNum);
    PRINTF("%lf",DoubleNum);
    PRINTF("%llf",LDNum);
    PRINTF("%llf+%llfi",creall(LDComplexNum),cimagl(LDComplexNum));
    PRINTF("%d",boolVar);
    PRINTF("%lu",sizeof(_Bool));

    return 0;
}


输出:

(intNum) ---> (3)
(longNum) ---> (3)
(LLNum) ---> (3)
(ShortNum) ---> (3)
(c) ---> (3)
(UShortNum) ---> (3)
(UIntNum) ---> (3)
(ULLNum) ---> (3)
(FloatNum) ---> (3.000000)
(DoubleNum) ---> (3.000000)
(LDNum) ---> (3.000000)
(creall(LDComplexNum),cimagl(LDComplexNum)) ---> (3.000000+3.000000i)
(boolVar) ---> (1)
(sizeof(_Bool)) ---> (1)

其他format指示符

%s

这个对应字符串,也很常用。

%p

输出指针指向的地址

其实是"%0[some number]X"

#include <stdio.h>

int main(){
    int a=3;
    int *b=&a;
    printf("%X\n",b);
    printf("%p\n",b);
}

结果:

61FE44
000000000061FE44
%a

https://stackoverflow.com/questions/4826842/the-format-specifier-a-for-printf-in-c

The %a formatting specifier is new in C99. It prints the floating-point number in hexadecimal form. This is not something you would use to present numbers to users, but it’s very handy for under-the-hood/technical use cases.

As an example, this code:

printf("pi=%a\n", 3.14);

prints:

pi=0x1.91eb86p+1

The excellent article linked in the comments explains that this should be read “1.91EB86_16 * 2^1” (that is, the p is for power-of-two the floating-point number is raised to). In this case, “1.91EB86_16” is “1.5700000524520874_10”. Multiply this by the “2^1”, and you get "3.140000104904175_10".

Note that this also has the useful property of preserving all bits of precision, and presenting them in a robust way.

%n

这个相当特殊,它不会输出任何东西。

这个参数必须对应一个有符号整数的指针(不过我实验过unsigned,也行),它存储它出现之前打印的所有字符数。

类似的,有%hn(short),%hhn(byte)

下面的代码在linux下跑没问题

但是在windows下,似乎有问题:%n无效,而且其后一直到换行符的内容都没了(包括换行符)

我花了一段时间在网上查找该问题的原因(我猜一定是系统或者MinGW的问题)。
果然我找到了:

printf()中%n格式说明符

Debug Assertion when using %n in printf

printf Type Field Characters

其实原因很简单:就是微软认为%n不安全,已经不再直接支持了。

解决办法也在上面官网文档里给出来了(_set_printf_count_output),不过我用MinGW试了一下之后报链接错误,这应该是头文件里有定义,但找不到函数体。所以没有成功,我也没有深究。

(顺带一提,java printf的%n表示兼容型换行符;linux换行\n, macOS是\r, windows是\r\n; java为了兼容,就自己搞出来个 %n; https://stackoverflow.com/questions/1883345/whats-up-with-javas-n-in-printf)

//以下代码在deepin中正常运行 (基于Debian的一种linux发行版,是国产的)

# include <stdio.h>

int main(void)
{
    int i = 46;
    printf("%d\n",i);
    //%n的作用:计算%n之前字符数量
    //如下面的xxxx,共4个
    //将结果放到对应整型指针指向的空间
    puts("(test 1)+++++++++++++++++++++++++++++++++");
    //举个例子
    printf("xxxx%n\n",&i);
    printf("%d\n",i);
    
    puts("(test 2)+++++++++++++++++++++++++++++++++");
    //转义字符是看成一个字符
    printf("x\\%%xxx%n\n",&i);
    printf("%d\n",i);

    puts("(test 3)+++++++++++++++++++++++++++++++++");
    //对拼接起来的字符串当成一个整体来看待
    printf("xxx" "xxx" "%n\n",&i);
    printf("%d\n",i);

    puts("(test 4)+++++++++++++++++++++++++++++++++");
    //对非ASCII字符,结果与其编码方式有关
    printf("你好%n\n",&i);
    printf("%d\n",i);

    puts("(test 5)+++++++++++++++++++++++++++++++++");
    //如果前面有 format specifier,则计算将他们转化为字符串之后的总长度
    printf("x%dxxx%n\n",100,&i);
    printf("%d\n",i);
    printf("x%dxxx%n\n",1000,&i);
    printf("%d\n",i);
    return 0;
}

结果:

46
(test 1)+++++++++++++++++++++++++++++++++
xxxx
4
(test 2)+++++++++++++++++++++++++++++++++
x\%xxx
6
(test 3)+++++++++++++++++++++++++++++++++
xxxxxx
6
(test 4)+++++++++++++++++++++++++++++++++
你好
6
(test 5)+++++++++++++++++++++++++++++++++
x100xxx
7
x1000xxx
8

子格式控制符

#include <stdio.h>

#define PRINTF(FORMAT, ...) \
    printf("format (\"%s\"): (%s) ---> (" FORMAT ")\n", FORMAT, #__VA_ARGS__, ##__VA_ARGS__);

#define __TEST__(N) printf("\n(__TEST__%3d)\n", (N));

int main()
{
    /*
    The format specifier can also contain sub-specifiers: flags, width, .precision
    and modifiers
    */

    int a = 11;
    //负号表示左对齐(默认右对齐)
    // 3表示要输出的字符的最小数目,不足补空格
    __TEST__(1);
    PRINTF("%-3d", a);

    // 0表示用0而不是空格来补全,经测试这种写法只有右对齐时才有效
    __TEST__(2);
    PRINTF("[%03d] [%-03d]", a, a);

    //*表示一个可以用整数替换的占位符,可以在运行时指定宽度
    //经过试验 %0*2d 这样也能生效,参数为1时,变成 %012d
    //不过不建议纠结于这种细节,会按照常规用法使用就行
    __TEST__(3);
    PRINTF("%0*d", 3, a);
    //虽然下面这样能运行,但别这样用,可读性太差
    //PRINTF("%0*2d", 1, a);

    //对正数补加号
    //不过对0也生效这点比较坑,估计是根据最高位是否为0判断正负的吧
    __TEST__(4);
    PRINTF("%+d", a);
    PRINTF("[%+d] [%+d]", 0, -0);
    PRINTF("[%-+3d] [%+-3d]", a, a);

    //%[若干空格][不写或者number]d
    //补足空格,但和 %[number]d 不同的是至少会保留一个空格
    __TEST__(5);
    PRINTF("% d", a);
    PRINTF("%   d", a);
    PRINTF("% 4d",a);
    PRINTF("% 2d",a);

    //%#[某格式控制符]
    // http://www.cplusplus.com/reference/cstdio/printf/

    //(1) o,x,X
    //    the value is preceeded with 0, 0x or 0X respectively for values
    //    different than zero.
    __TEST__(6);
    PRINTF("%o", a);
    PRINTF("%#o", a);
    PRINTF("%x", a);
    PRINTF("%#x", a);
    //(2) a, A, e, E, f, F, g or G
    //    it forces the written output to contain a decimal point even if no more
    //    digits follow. By default, if no digits follow, no decimal point is
    //    written.
    __TEST__(7);
    PRINTF("%g", (float)(a));
    PRINTF("%#g", (float)(a));

    // (%.precision(精度))
    //(这个可能是最麻烦的了)

    //(1) d, i, o, u, x, X
    //    precision 指定了要写入的数字的最小位数。
    //    如果写入的值短于该数,结果会用前导零来填充。
    //    如果写入的值长于该数,结果不会被截断。
    //    精度为 0 意味着不写入任何字符。
    __TEST__(8);
    //%03d 有点像;不同在于如果用%-.3d,左对齐无效
    PRINTF("[%.3d] [%-.3d]", a, a);

    //(2) e,E,f
    //    要在小数点后输出的小数位数,规则是“四舍五入”
    //    %f 默认情况下其实是%.6f
    __TEST__(9);
    PRINTF("%.3f", 0.123456);
    PRINTF("%.3f", 0.666666);
    PRINTF("%.3f", 0.555555);
    PRINTF("%.3f", 0.444555);
    PRINTF("%.3f", 0.444545);
    PRINTF("%08.2f", 33.3333);
    //(3) g,G
    //    要输出的最大有效位数
    __TEST__(10);
    PRINTF("%.3g", 31.123456);
    PRINTF("%.3g", 1231231.123456);

    //(4) s
    //    要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
    __TEST__(11);
    PRINTF("%.3s", "hahahahahahah");

    //(5) c [无影响]
    __TEST__(12)
    PRINTF("%.123c", 'a');

    //(6) If the period is specified without an explicit value for precision, 0 is assumed.
    //*******************************
    // 关于这点,网上搜到的基本上是下面这句:
    //  """当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。"""
    // 其实这一句我之前没理解,实验的时候,%.s 那就是默认0啊。
    // 直到我到 http://www.cplusplus.com/reference/cstdio/printf/ 看了英文原版。。。
    // 前面那条 “默认为1” 根本就没有。。。。。。。。。。。
    // 果然还是英文资料比较好啊。。。
    //*******************************
    __TEST__(13)
    PRINTF("%.f", 33.3333);
    PRINTF("%.s", "hahahahahahah");

    //(6) %.*
    //   其实这个和%*d那个用法一样,就不多说了
    __TEST__(14);
    PRINTF("%.*f", 4, 0.123456);
}

结果:

(__TEST__  1)
format ("%-3d"): (a) ---> (11 )

(__TEST__  2)
format ("[%03d] [%-03d]"): (a, a) ---> ([011] [11 ])

(__TEST__  3)
format ("%0*d"): (3, a) ---> (011)

(__TEST__  4)
format ("%+d"): (a) ---> (+11)
format ("[%+d] [%+d]"): (0, -0) ---> ([+0] [+0])
format ("[%-+3d] [%+-3d]"): (a, a) ---> ([+11] [+11])

(__TEST__  5)
format ("% d"): (a) ---> ( 11)
format ("%   d"): (a) ---> ( 11)
format ("% 4d"): (a) ---> (  11)
format ("% 2d"): (a) ---> ( 11)

(__TEST__  6)
format ("%o"): (a) ---> (13)
format ("%#o"): (a) ---> (013)
format ("%x"): (a) ---> (b)
format ("%#x"): (a) ---> (0xb)

(__TEST__  7)
format ("%g"): ((float)(a)) ---> (11)
format ("%#g"): ((float)(a)) ---> (11.0000)

(__TEST__  8)
format ("[%.3d] [%-.3d]"): (a, a) ---> ([011] [011])

(__TEST__  9)
format ("%.3f"): (0.123456) ---> (0.123)
format ("%.3f"): (0.666666) ---> (0.667)
format ("%.3f"): (0.555555) ---> (0.556)
format ("%.3f"): (0.444555) ---> (0.445)
format ("%.3f"): (0.444545) ---> (0.445)
format ("%08.2f"): (33.3333) ---> (00033.33)

(__TEST__ 10)
format ("%.3g"): (31.123456) ---> (31.1)
format ("%.3g"): (1231231.123456) ---> (1.23e+006)

(__TEST__ 11)
format ("%.3s"): ("hahahahahahah") ---> (hah)

(__TEST__ 12)
format ("%.123c"): ('a') ---> (a)

(__TEST__ 13)
format ("%.f"): (33.3333) ---> (33)
format ("%.s"): ("hahahahahahah") ---> ()

(__TEST__ 14)
format ("%.*f"): (4, 0.123456) ---> (0.1235)

相关库函数


printf // 用于打印信息
scanf // 用于输入(不过用起来和printf的有所区别,我还没深究)

//上两个函数的safe版本,这是c11标准的
//如果用 VS2015 写代码时使用 scanf 可能会提示换成 scanf_s
//如果有理由不能换,则可加 #pragma warning(disable:4996)
printf_s 
scanf_s 

sprintf // 格式化字符串
fprintf // 写到文件


// https://en.cppreference.com/w/c/io/fprintf
Defined in header <stdio.h>int printf( const char *format, ... );(until C99)int printf( const char *restrict format, ... );(since C99)


int fprintf( FILE *stream, const char *format, ... );
(until C99)

int fprintf( FILE *restrict stream, const char *restrict format, ... );
(since C99)

int sprintf( char *buffer, const char *format, ... );
(until C99)

int sprintf( char *restrict buffer, const char *restrict format, ... );
(since C99)

int snprintf( char *restrict buffer, size_t bufsz, 
              const char *restrict format, ... );
(since C99)

int printf_s(const char *restrict format, ...);
(since C11)


int fprintf_s(FILE *restrict stream, const char *restrict format, ...);
(since C11)


int sprintf_s(char *restrict buffer, rsize_t bufsz,
              const char *restrict format, ...);
(since C11)

int snprintf_s(char *restrict buffer, rsize_t bufsz,
               const char *restrict format, ...);
(since C11)

printf 缓冲区(缓存区)问题

fprintf函数,stdout,stderr,缓冲区

  1. stdout 是标准输出,stderr 是标准错误
  2. stdout 是有缓冲区的,stderr 没有缓冲区(为了立即输出错误)
  3. printf(…) 其实等价于 fprintf(stdout,…),所以是有缓冲区的
  4. 如果缓冲区不被刷新,那么printf是不会将缓冲区里暂存的内容输出到显示区的
  5. 一般情况下,stdout和stderr用起来似乎没有区别,但如果在运行期遇到异常时,他们表现出来的差异比较大。如果用stdout,在刷新前遇到异常,程序终止,那不会输出任何东西。另外如果混用两者,则不能保证输出的顺序符合预期。

什么是缓冲区

https://www.cnblogs.com/csdndreamer/p/5490660.html

缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

为什么需要缓冲区

协调低速的IO设备和高速的CPU,使整个系统高效工作。

缓冲区类型

缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。

  1. 全缓冲

在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

  1. 行缓冲

在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。

  1. 不带缓冲

也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

缓冲区的大小

https://www.jianshu.com/p/bd4fc453215b

如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是512个字节的大小。

缓冲区大小由 stdio.h 头文件中的宏 BUFSIZ 定义,如果希望查看它的大小,包含头文件,直接输出它的值即可:printf("%d", BUFSIZ);

缓冲区的大小是可以改变的,也可以将文件关联到自定义的缓冲区,详情可以查看 setvbuf()setbuf() 函数。

缓冲区什么时候会被刷新(清空)

https://www.jianshu.com/p/bd4fc453215b

下列情况会引发缓冲区的刷新:缓冲区满时;行缓冲区遇到回车时;关闭文件;使用特定函数刷新缓冲区。

  1. 程序正常退出(正常结束),如exit(0),main函数里return 0 .
  2. 遇到 \n , \r 时会刷新缓冲区.
  3. 缓冲区满时自动刷新.
  4. 关闭文件(如果是在文件读写的情景下)
  5. 手动刷新
    • 调用 fflush 标准库函数:
      • #include <stdio.h>
      • int fflush(FILE *stream)
    • C++ 的 std::endl
      • 其实C++的endl有刷新缓冲区的作用,但这篇博客是讲C的,就不多说了。
    • C++ unitbuf操纵符
  6. 调用某些函数时,会自动刷新缓冲区:
    • https://blog.csdn.net/Infect_your_breath/article/details/75944176
    • scanf()函数在缓存里面读数据时,会先将缓存区刷新,然后再读取数据。另外getc()、gets()、fgetc()、fgets()这几个读取数据时,也会会先将缓存区刷新,然后再读取数据。当然gets()是不建议使用的,就差被逐出标准了。

getchar, getch, getche 的区别:

  1. getchar 从缓冲区中读取字符
  2. getch 非标准库函数,要包含 conio.h。 从键盘读取字符(常用来实现“按任意键继续”),不回显
  3. getche 非标准库函数,要包含 conio.h。 头文件(unix系列平台的编译器一般不包含这个头文件),与getch唯一的不同:会回显

详情请见下面这篇博客:
https://www.jianshu.com/p/bd4fc453215b


其他

%x、%X、%#x、%#X 的区别

# include <stdio.h>

# define PRINTF(FORMAT,...) printf("format (%s) output: "FORMAT"\n",FORMAT,__VA_ARGS__);

int main(void)
{
    int i = 46;
    PRINTF("%x",i);
    PRINTF("%X",i);
    PRINTF("%#x",i);
    PRINTF("%#X",i);
    return 0;
}

结果

format (%x) output: 2e
format (%X) output: 2E
format (%#x) output: 0x2e
format (%#X) output: 0X2E

关于大写输出 (%X %G %E %A)

如果输出的格式中可能带有字母,想要大写输出就可以用对应的大写字母格式符。

%X %G %E %A

但不是所有格式控制符都有对应大写版本,比如下面这几个就是无效的:

//无效
printf("%D\n",3);
printf("%S\n","asfsdfas");

而这几个是有效的:

//有效
printf("%X\n",333);
printf("%E\n",333.333);
printf("%G\n",333.333);
printf("%A\n",333.333);

/*
输出为:
14D
3.333330E+002
333.333
0X1.4D553FP+8
*/

关于%I64d%lld

这是一篇关于这个问题的博客,2014年以前的

//由于64位整数在最初并不是标准的一部分
//导致后来编译器各自实现自己的标准
//这就出现了不兼容的 %I64d 和 %lld
//不过据说后来是都可以了,没实验过(虽然我不信)

如何输出 %d、\ 和双引号

这是一片讲解printf的博客,我觉得还不错

# include <stdio.h>
int main(void)
{
    printf("%%d\n"); // 两个百分号输出百分号
    printf("\\\n"); // 两个反斜杠表示反斜杠
    printf("\"\"\n"); // 使用转义字符的表示双引号
    return 0;
}

如果 printf %d 后不提供参数会怎么样?

Behaviour of printf when printing a %d without supplying variable name

#include <stdio.h>

int main() {
  /*
    下面代码我某次执行结果是这样的:
    13384896
    726006320
    726006320
    726006320
    726006320
    这显然不是随机数这么简单的问题

    事实上这时printf的行为与编译器有关
    不同编译器下,可能会有不同结果,有的甚至可能会报错

    上面这些是printf从stack里取得的垃圾数据
    我们不应该让这种情况发生
   */
  //(注意,C89 不允许for里int)
  for (int i = 0; i < 5; i++) {
    // printf %d with out supplying variable...
    printf("%d\n");
  }
  return 0;
}

利用C11特性 _Generic 写的泛型print

源自这篇博客

https://blog.csdn.net/qq_31243065/article/details/80904613

// 注意,我这里用的是新版的gcc (支持C11)
// 如果用其他编译器不能保证编译成功
//
// 说起来我上个星期对C语言的认知还是“古老”
// 这个星期听说了C11后才对C改观

#include <stdio.h>
#include <stdbool.h>
#include <complex.h>

#define PRINT_VAR_NAME(A) printf("%s ---> ",(#A))
#define CUSTOM_GENERIC(A) _Generic((A), \
/*signed char*/                 signed char : printf("type signed char, var:%d\n", (A)), \
/*signed short*/                signed short : printf("type signed short, var:%hd\n", (A)), \
/*signed int*/                  signed int : printf("type signed int, var:%d\n", (A)), \
/*signed long int */            signed long int : printf("type signed long int, var:%ld\n", (A)), \
/*signed long long int*/        signed long long int : printf("type signed long long int, var:%lld\n", (A)), \
/*unsigned char*/               unsigned char : printf("type unsigned char, var:%c\n", (A)), \
/*unsigned short*/              unsigned short : printf("type unsigned short, var:%hu\n", (A)), \
/*unsigned int*/                unsigned int : printf("type unsigned int, var:%u\n", (A)), \
/*unsigned long int*/           unsigned long int : printf("type unsigned long int, var:%lu\n", (A)), \
/*unsigned long long int*/      unsigned long long int : printf("type unsigned long long int, var:%llu\n", (A)), \
/*float*/                       float : printf("type float, var:%f\n", (A)), \
/*double*/                      double : printf("type double, var:%lf\n", (A)), \
/*long double*/                 long double : printf("type long double, var:%llf\n", (A)),  \
/*_Bool*/                       _Bool : printf("type _Bool, var:%d\n", (A)),  \
/*float _Complex*/              float _Complex : printf("type float _Complex, var:%f+%fi\n", crealf((A)), cimagf((A))),  \
/*double _Complex*/             double _Complex : printf("type double _Complex, var:%lf+%lfi\n", creal((A)), cimag((A))),  \
/*long double _Complex*/        long double _Complex : printf("type long double _Complex, var:%llf+%llfi\n", creall((A)), cimagl((A))),  \
/*default*/                     default : printf("type default!\n") \
)

# define MY_PRINT(X) {\
    PRINT_VAR_NAME(X);\
    CUSTOM_GENERIC(X);\
}


int main(){
    int intNum = 3;
    long longNum = 3L;
    long long LLNum = 3LL;
    short ShortNum = 3;
    char c='3';
    unsigned short UShortNum = 3U;
    unsigned int UIntNum = 3U;
    unsigned long long ULLNum = 3ULL;
    float FloatNum = 3.0f;
    double DoubleNum = 3.0;
    long double LDNum = 3.0;

    //C99新类型
    _Bool boolVar = true; // 注意,这里的 true 只是一个宏而已(int的1),和C++的true是不同的
    long double _Complex LDComplexNum = 3.0+3.0I;// 或者 3+3×I,I是complex.h里的宏 
    
    MY_PRINT(intNum);
    MY_PRINT(longNum);
    MY_PRINT(LLNum);
    MY_PRINT(ShortNum);
    MY_PRINT((signed char)(c));
    MY_PRINT((unsigned char)(c));
    MY_PRINT(c);
    MY_PRINT(UShortNum);
    MY_PRINT(UIntNum);
    MY_PRINT(ULLNum);
    MY_PRINT(FloatNum);
    MY_PRINT(DoubleNum);
    MY_PRINT(LDNum);
    MY_PRINT(boolVar);
    MY_PRINT(LDComplexNum);
    MY_PRINT(sizeof(_Bool));

    return 0;
}

输出:

intNum ---> type signed int, var:3
longNum ---> type signed long int, var:3
LLNum ---> type signed long long int, var:3
ShortNum ---> type signed short, var:3
(signed char)(c) ---> type signed char, var:51
(unsigned char)(c) ---> type unsigned char, var:3
c ---> type default!
UShortNum ---> type unsigned short, var:3
UIntNum ---> type unsigned int, var:3
ULLNum ---> type unsigned long long int, var:3
FloatNum ---> type float, var:3.000000
DoubleNum ---> type double, var:3.000000
LDNum ---> type long double, var:3.000000
boolVar ---> type _Bool, var:1
LDComplexNum ---> type long double _Complex, var:3.000000+3.000000i
sizeof(_Bool) ---> type unsigned long int, var:1
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值