详解C语言输出打印

《C语言printf函数的高级用法》阅读

头文件

printf 来自C语言头文件 stdio.h(标准IO),是C语言常用来打印日志的API。

#include <stdio.h>

cout 则来自 C++ 头文件 iostream

#include <iostream>

格式化参数

使用 printf 的一个难点就是掌握格式化参数。

通常来说,格式化参数所表示的类型与变量的实际类型一致,才能打印出正确的结果。,比如

  • 声明一个 int 变量,就用 %d 来格式化该变量的值。
  • 声明一个 unsigned int 变量,就用 %u 来格式化该变量的值。

以下测试环境为

  • Windows 操作系统
  • Visual Studio
  • Win32 项目

1. 打印字符串(常用)

在C语言中,我们常用 char数组表示字符串:

#include <stdio.h>
int main() {
  char str[] = "Hello";
  printf("%s\n", str);
  return 0;
}

2. 打印整数(常用)

《C语言的整数类型》 阅读

  • %d 十进制有符号整数
  • %u 十进制无符号整数

C语言中,带符号的标准整数类型有 char,short,int,long,long long。

1、用%d格式化范围内的正整数:

char c = 97;
short s = 128;
int i = 1024;
long l = 65500;
long long ll = 131070;
printf("%d\n", c); // 输出97
printf("%u\n", c); // 输出97
printf("%d\n", s); // 输出128
printf("%u\n", s); // 输出128
printf("%d\n", i); // 输出1024
printf("%u\n", i); // 输出1024
printf("%d\n", l); // 输出65500
printf("%u\n", l); // 输出65500
printf("%d\n", ll); // 输出131070
printf("%u\n", ll); // 输出131070

2、用%d格式化超出范围的正整数:

char c = 128; // char范围是 -128~127
short s = 32768; // short范围是 -32768~32767
int i = 2147483648; // int范围是 -2147483648~2147483647
long l = 2147483648;// long范围是 -2147483648~2147483647
long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%d\n", c); // 输出-128
printf("%u\n", c); // 输出4294967168
printf("%d\n", s); // 输出-32768
printf("%u\n", s); // 输出4294934528
printf("%d\n", i); // 输出-2147483648
printf("%u\n", i); // 输出2147483648
printf("%d\n", l); // 输出-2147483648
printf("%u\n", l); // 输出2147483648
printf("%d\n", ll); // 输出0
printf("%u\n", ll); // 输出0
  • char的长度为1个字节,128 用1个字节表示等于 0x80,被解释为有符号十进制整数 -128,因此 %d 格式化后输出 -128;
  • short的长度为2个字节,32768 用2个字节表示等于 0x8000,被解释为有符号十进制整数 -32768,因此 %d 格式化后输出 -32768;
  • int和long的长度为4个字节,2147483648 用4个字节表示等于 0x80000000,被解释为有符号十进制整数 -2147483648,因此 %d 格式化后输出 -2147483648;

上述的几种情况,我们在定义的时候,可以采用无符号数来声明整型变量:

unsigned char c = 128; // char范围是 -128~127
unsigned short s = 32768; // short范围是 -32768~32767
unsigned int i = 2147483648; // int范围是 -2147483648~2147483647
unsigned long l = 2147483648;// long范围是 -2147483648~2147483647
printf("%d\n", c); // 输出128
printf("%u\n", c); // 输出128
printf("%d\n", s); // 输出32768
printf("%u\n", s); // 输出32768
printf("%d\n", i); // 输出-2147483648
printf("%u\n", i); // 输出2147483648
printf("%d\n", l); // 输出-2147483648
printf("%u\n", l); // 输出2147483648
  • 我们发现int和long在格式化为%d%u时还是有所不同。

为了解决 long long 类型 printf 打印结果为 0 的问题,引入了格式化参数 %lld%llu ,可以表示 64位(8字节)的整型数。

long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%lld\n", ll); // 输出-9223372036854775808
printf("%llu\n", ll); // 输出9223372036854775808

3、可以在“%”和字母之间插进数字表示最小宽度
%3d中,d表示以十进制输出,3表示最少占3个字符的宽度,宽度不足以空格补齐,默认右对齐。综合起来,%3d表示以十进制输出,右对齐,宽度最小为3个字符。

char c = 1; // char范围是 -128~127
short s = 1; // short范围是 -32768~32767
int i = 1; // int范围是 -2147483648~2147483647
long l = 1;// long范围是 -2147483648~2147483647

printf("%3d\n", c);
printf("%5d\n", s);
printf("%10d\n", i);
printf("%10d\n", l);

printf("%3d\n", -c);
printf("%5d\n", -s);
printf("%10d\n", -i);
printf("%10d\n", -l);

输出结果如下图:

还可以用 %03d 表示输出3位整型数,宽度不够3位,左边补0 :

char c = 1;
short s = 1;
int i = 1;
long l = 1;
printf("%03d\n", c);
printf("%05d\n", s); 
printf("%010d\n", i);
printf("%010d\n", l);

printf("%03d\n", -c);
printf("%05d\n", -s);
printf("%010d\n", -i);
printf("%010d\n", -l);

输出结果如图所示:

我们再来看一下,超出最小宽度的情况:

char c = -127;
short s = -32767;
int i = -2147483647;
long l = -2147483647;

printf("%03d\n", c);
printf("%05d\n", s); 
printf("%010d\n", i);
printf("%010d\n", l);

printf("%03d\n", -c);
printf("%05d\n", -s);
printf("%010d\n", -i);
printf("%010d\n", -l);

如图所示,负号也占一个字符位:

刚才看的是右对齐,现在再来看一下左对齐

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a1=20, a2=345, a3=700, a4=22;
    int b1=56720, b2=9999, b3=20098, b4=2;
    int c1=233, c2=205, c3=1, c4=6666;
    int d1=34, d2=0, d3=23, d4=23006783;
    printf("%-9d %-9d %-9d %-9d\n", a1, a2, a3, a4);
    printf("%-9d %-9d %-9d %-9d\n", b1, b2, b3, b4);
    printf("%-9d %-9d %-9d %-9d\n", c1, c2, c3, c4);
    printf("%-9d %-9d %-9d %-9d\n", d1, d2, d3, d4);
    system("pause");
    return 0;
}

输出结果如图所示:

3. 打印16进制数

  • %o 无符号以八进制表示的整数; 八进制我们在编程时用得不多,再次就不展示了。

  • %x, %X 无符号以十六进制表示的整数(常用,打印指针一般会用到这个)

    %x 表示字母小写,%X 表示字母大写

unsigned char c = 128; // char范围是 -128~127
unsigned short s = 32768; // short范围是 -32768~32767
unsigned int i = 2147483648; // int范围是 -2147483648~2147483647
unsigned long l = 2147483648;// long范围是 -2147483648~2147483647
long long ll = 9223372036854775808; // long long 范围 -9223372036854775808~9223372036854775807
printf("%x\n", c); // 输出80
printf("%x\n", s); // 输出8000
printf("%x\n", i); // 输出80000000
printf("%x\n", l); // 输出80000000
printf("%llx\n", ll); // 输出8000000000000000
  • 注意使用 %x 格式化超过32位所能表示的值时,会输出0。因此,需要改用 %llx 格式化64位的整型;

  • 如果打印16进制数时需要0x前缀,可以选用格式化参数 %#x

4. 打印浮点数

  • %f 浮点数
  • %e 指数形式的浮点数
float f = 3.4028235E38;  // float 的范围是 [-3.4028235E38, 3.4028235E38]
double d = 3.4028235E50;
printf("%f\n", f);  // 输出 340282346638528860000000000000000000000.000000
printf("%e\n", f);  // 输出 3.402823e+038
printf("%f\n", d);  // 输出 340282350000000000000000000000000000000000000000000.000000
printf("%e\n", d);  // 输出 3.402824e+050
printf("%lf\n", d); // 输出 340282350000000000000000000000000000000000000000000.000000

打印浮点数时,常常要求保留精度:

float f = 3.4028235E38;  // float 的范围是 [-3.4028235E38, 3.4028235E38]
double d = 3.4028235E50;
printf("%.2f\n", f);  // 输出 340282346638528860000000000000000000000.00
printf("%.2e\n", f);  // 输出 3.40e+038
printf("%.3f\n", d);  // 输出 340282350000000000000000000000000000000000000000000.000
printf("%.3e\n", d);  // 输出 3.403e+050
printf("%.1lf\n", d); // 输出 340282350000000000000000000000000000000000000000000.0

5. 打印单个字符

%c 单个字符(常用)

char a = 'a';
int b = 98;
printf("%c\n", a); // 输出a
printf("%c\n", b); // 输出b

6. 打印指针

%p 指针

char str[] = {'G', 'o', 'd', '\0'};
printf("%p", str);    // 在一次实验中,输出00F3FBCC 
printf("%p\n", &str); // 在一次实验中,输出00F3FBCC
printf("%c\n", *str); // 输出G

如下图所示:

其中,0x00F3FBCC 是指针的首地址。对应的内存地址为:

自定义日志输出

/*=================================
 *  自定义打印输出
 ==================================*/
#define INFO_OUTPUT         3
#define WARNING_OUTPUT      2
#define DEBUG_OUTPUT        1
#define ERROR_OUTPUT        0

#define DEBUG
#define DEBUG_LEVEL         INFO_OUTPUT

#define PRINT(info, ...) do{ \
    printf("[Info] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}while(0)

#define INFO_PRINT(info, ...) do{ \
    if(DEBUG_LEVEL>=INFO_OUTPUT){ \
        printf("[Info] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
    } \
}while(0)

#define WARNING_PRINT(info, ...) do{ \
    if(DEBUG_LEVEL>=WARNING_OUTPUT){ \
        printf("[Warning] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
    } \
}while(0)

#define DEBUG_PRINT(info,...) do{ \
    if(DEBUG_LEVEL>=DEBUG_OUTPUT){ \
        printf("[Debug] (%s:%d->%s):" info"",__FILE__,__FUNCTION__,__LINE__,##__VA_ARGS__); \
    } \
}while(0)

#define ERROR_PRINT(info, ...) do{ \
    if(DEBUG_LEVEL>=ERROR_OUTPUT){ \
        printf("[Error] (%s:%d->%s):" info"", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
    } \
}while(0)
posted @ 2021-06-07 20:02  极客子羽  阅读(7123)  评论(0编辑  收藏  举报