缺一不可 Windows Native (4)

不可或缺 Windows Native (4)

[源码下载]


不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出



作者:webabcd


介绍
不可或缺 Windows Native 之 C 语言

  • 预处理命令
  • 输入
  • 输出



示例
1、预处理命令
cPreprocessor.h

#ifndef _MYHEAD_PREPROCESSOR_
#define _MYHEAD_PREPROCESSOR_ 

#ifdef __cplusplus  
extern "C"
#endif  

char *demo_cPreprocessor();

#endif  

cPreprocessor.c

/*
 * 预处理命令
 *
 * 以“#”开头的就是预处理命令(预处理命令不用“;”结尾),其是指在编译之前所做的工作
 */

#include "pch.h"
#include "cPreprocessor.h"
#include "cHelper.h"



// #define - 宏定义命令,在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”
#define PI 1000 //  #define 标识符 字符串
#define S PI * r * r // 一个宏也可以引用另一个宏
#define S2(r) PI * r * r // 宏是可以带参数的
#define PI 3.14 // 宏重名的话,后面的会替换前面的
#define INTEGER int // 宏定义当然也可以定义数据类型,因为其本质就是拿一个字符串替换另一个字符串
#define ISWINDOWS 1
#define X(n) n == 0 ? 0 \
    : -1 // 一个长的 #define 可以用“\”分成多行


// 说到这里再插一句,单行注释的话 \
以“\”结尾则下一行也为注释 \
另外:ANSI C 只支持“/**/”注释,而不支持“//”注释


/*
再强调一遍,宏替换的本质就是拿一个字符串替换另一个字符串

如果是 #define x 1 + 2
那么表达式 3 * x * 4 就相当于 3 * 1 + 2 * 4,结果是 11
如果是 #define x (1 + 2)
那么表达式 3 * x * 4 就相当于 3 * (1 + 2) * 4,结果是 36
*/



/*
#include - 文件包含命令

#include "stdio.h" 使用双引号表示首先在文件当前目录中查找(支持绝对路径和相对路径),若未找到则到包含目录中去查找
#include <math.h> 使用尖括号表示在包含文件目录中去查找,而不在文件当前目录去查找

包含文件目录的设置:项目 -> 右键 -> 属性 -> 配置属性 -> VC++ 目录 -> 包含目录
*/



char *demo_cPreprocessor()
{
    INTEGER r = 2; // 宏展开其相当于 int r = 2;
    float x = S; // 宏展开其相当于 3.14 * r * r,即 3.14 * 2 * 2

    float y = S2(2); // 宏展开其相当于 3.14 * 2 * 2

    int z = X(100); // -1

    

// 条件编译命令有:#ifdef, #else, #endif, #ifndef, #if
#ifdef PI // 如果在宏定义中定义了 PI(ifdef 是 if defined 的简写)
    ;
#else // 如果不需要的话,可以不要 #else
    ;
#endif  // #ifdef 和 #endif 必须成对


#ifndef PI // 如果在宏定义中没有定义 PI(ifndef 是 if not defined 的简写)
    ;
#else // 如果不需要的话,可以不要 #else
    ;
#endif // #ifndef 和 #endif 必须成对


#if ISWINDOWS // 如果宏定义 ISWINDOWS 非零则为真(ISWINDOWS 是整型)
    ;
#else // 如果不需要的话,可以不要 #else
    ;
#endif // #if 和 #endif 必须成对



    return float_toString(y);
}


// 这之后不再有 PI 这个宏定义(undef 是 undefine 的简写)
#undef PI


2、输入和输出
cIO.h

#ifndef _MYHEAD_IO_
#define _MYHEAD_IO_ 

#ifdef __cplusplus  
extern "C"
#endif  

char *demo_cIO();

#endif  

cIO.c

/*
 * 输入,输出
 */

#include "pch.h"
#include "cIO.h"
#include "cHelper.h"

void io_printf();
void io_scanf();
void io_putchar();
void io_getchar();

char *demo_cIO()
{
    // 格式化输出 printf
    io_printf();

    // 格式化输入 scanf
    io_scanf();

    // 字符输出 putchar()
    io_putchar();

    // 字符串输入 getchar()
    io_getchar();

    return "看代码及注释吧";
}


// 格式化输出 printf
void io_printf()
{
    // printf - print formatted,以下仅列一下常用用法
    // printf 的返回值为:实际输出的字符数

    int a = 88;
    float b = 3.14159;
    char *c = "webabcd wanglei";


    // %d - 以十进制形式输出带符号整数
    // %.2f - 以浮点型输出,取小数点后 2 位
    // %.7s - 以字符串输出,取前 7 位
    printf("%d, %.2f, %.7s\n", a, b, c);
    // 输出结果:88, 3.14, webabcd
    // printf 的返回值为 18


    // %o - 以八进制形式输出无符号整数
    // %#o - 以八进制形式输出无符号整数,并加前缀 0
    printf("%o, %#o\n", a, a);
    // 输出结果:130, 0130


    // %x 或 %X - 以十六进制形式输出无符号整数
    // %#x - 以八进制形式输出无符号整数,并加前缀 0x
    // %#X - 以八进制形式输出无符号整数,并加前缀 0X
    printf("%x, %#x, %#X\n", a, a, a);
    // 输出结果:58, 0x58, 0X58


    // %10.2f - 以浮点型输出,取小数点后 2 位;显示宽度至少为 10 位,不够以空格填充
    printf("%10.2f\n", b);
    // 输出结果:      3.14(前面有 6 个空格)



    /*
    * 类型说明如下:
    * %d / %i - 整型
    * %o - 无符号八进制
    * %u - 无符号十进制
    * %x / %X - 无符号十六进制
    * %f / %F - 浮点型
    * %e / %E - 科学表示法(%e后面就输出小写e;%E后面就输出大写E)
    * %g / %G - 浮点型,但是会去掉小数后面多余的 0,然后在 %f 和 %e 之中选一个最短的形式输出
    * %c - 字符
    * %s - 按字符串输出,直至'\0'
    * %p - 以十六进制形式输出指针
    * %% - %
    *
    *
    * 另外有两种长度格式:
    * h - 按短整型量输出,比如:%hd - 按短整型输出; printf("%hd", 32769) 输出结果为 -32767
    * l - 按长整型量输出,比如:%lf - 按 double 输出; %ld - long int; %lld - long long int
    */

    float x = 3.14f;
    printf("%f", x); // 3.140000
    printf("%g", x); // 3.14

    float y = 12345678.123456f;
    printf("%e", y); // 1.234568e+07
    printf("%f", y); // 12345678.000000
    printf("%G", y); // 1.23457E+07(另外,比 %e 少一位小数)
}


// 格式化输入 scanf
void io_scanf()
{
    // scanf - scan formatted,以下仅列一下常用用法
    // printf 的返回值为:成功接收到的赋值参数的个数

    int a;
    float b;
    char c[100];


    // %2s - 代表输入字符串时,只取前 2 位
    // 如果在两个格式化参数之间没有它字符的话,则可用空格或TAB或回车做间隔
    scanf("%d%f%2s", &a, &b, c);
    // 输入 1 3.14 webabcd 后的结果为:a 的值为 1,b 的值为 3.14,c 的前 3 个元素为 'w' 'e' '\0'
    // scanf 的返回值为 3


    // 如果在两个格式化参数之间有它字符的话,则按指定的字符做间隔
    scanf("a=%d, b=%f, c=%s", &a, &b, c);
    // 输入:a=1, b=3.14, c=webabcd
}


// 字符输出 putchar()
void io_putchar()
{
    // 输出一个字符
    putchar('a');
}


// 字符串输入 getchar()
void io_getchar()
{
    // 当程序调用 getchar() 函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)
    // 当用户键入回车之后,getchar() 函数才开始从键盘缓冲区中每次读入一个字符,一直到缓冲区中的字符读完

    /*
    char c = NULL;
    while ((c == getchar()) != '\n') 
    {
        printf("%c", c);
    }
    */

    // getch(), getche() 之类的需要 conio.h, 但是在 linux 下是没有的,所以就不写了
}



OK
[源码下载]

8楼garbageMan
引用#define S PI * r * r // 一个宏也可以引用另一个宏,#define S2(r) PI * r * r // 宏是可以带参数的,,任何一个合格的程序员都不会这样写宏。,误导他人。
7楼garbageMan
引用再强调一遍,宏定义的本质就是拿一个字符串替换另一个字符串,概念错误。
6楼garbageMan
引用* 另外有两种长度格式:, * h - 按短整型量输出,比如:%hd - 按短整型输出; printf(quot;%hdquot;, 32769) 输出结果为 -32767, * l - 按长整型量输出,比如:%lf - 按 double 输出; %ld - long int; %lld - long long int,至少有两处错误
5楼garbageMan
引用* %g / %G - 在 %f 和 %e/%E 之中选一个最短的形式,错。,这个是从老谭的胡扯中学来的吧
4楼garbageMan
引用* %s / %S - 按字符串输出,直至#39;\0#39;,%S是你瞎编的吧?
3楼garbageMan
引用#include quot;stdio.hquot; 使用双引号表示首先在文件当前目录中查找(支持绝对路径和相对路径),若未找到则到包含目录中去查找,#include lt;math.hgt; 使用尖括号表示在包含文件目录中去查找,而不在文件当前目录去查找,错
2楼garbageMan
引用// %.2f - 以浮点型输出,取小数点后 2 位,转换格式根本就不存在“型”这个概念
1楼garbageMan
引用scanf(quot;a=%d, b=%f, c=%squot;, amp;a, amp;b, c);, // 输入:a=1, b=3.14, c=webabcd,喜欢自虐?,竟然设计这么变态的格式
Re: webabcd
@garbageMan,1、只是为了说明用法,2、宏替换是替换字符串,3、哪错了?请指点一下,4、也许我表达有问题,5、嗯,网上抄来的,描述不完全,再更新一下,多谢指出,%g / %G - 浮点型,但是会去掉小数后面多余的 0,然后在 %f 和 %e 之中选一个最短的形式输出,6、嗯,真实瞎编的,已经去掉了,多谢指正,7、哪错了?请指点一下,8、只是为了说明用法