• C专家编程 第1章 C:穿越时空的迷雾 1.3 标准I/O库和C预处理器


    标准I/O库和C预处理器 
        C编译器不曾实现的一些功能必须通过其他途径实现。在C语言中,它们在运行时进行处理,既可以出现在应用程序代码中,也可以出现在运行时函数库中(runtime library)。在C语言中,绝大多数库函数或辅助程序都需要显式调用。例如, C语言(必要时),程序员必须管理动态内存的使用,创建各种大小的数组,测试数组边界,进行范围检测。

        C原先并没有定义I/O,而是由库函数提供。后来,这实际上成了标准机制。 
        可移植的I/O由Mike Lesk编写,最初出现在1972年,经过优化和裁剪后来成为标准I/O函数库。 

         C预处理器 
         倡仪者:Alan Snyder 
         时间:1972  
         实现的3个主要功能:
         字符串替换。通常用于为常量提供一个符号名。 

         头文件包含。(一般性的声明被分离到头文件中,并且可以被许多源文件使用,虽然约定采用以.h作为头文件的扩展名) 

         通用代码模板的扩展。与函数不同,宏(marco)在连续几个调用中所接收的参数的类型可以不同(宏的实际参数只是按照原样输出)在宏的扩展中,空格会对扩展造成很大的影响。 

        //1.
        #define a(y) a_expanded(y)
        a(x);
        被扩展为 
        a_expanded(x);
        
        #define a (y) a_expanded(y)
        a(x);
        被扩展为 
        (y) a_expanded(y)(x);

        你可能会以为在宏里面使用花括号就像在C语言的其他部分一样,能把多余语句组合成一条复合语句,但实际上并非如此。对于宏这样的预处理器,只应该适量使用。 

        //2.
        /*人物:Steve Bourne 
         *地点:贝尔实验室
         *UNIX第7版的Shell(命令解释器)
         *使用预处理器使C语言看上去更像Algol-68 
         */
        #define STRING char *
        #define IF if (
        #define THEN ) {
        #define ELSE } else (
        #define FI ;}
        #define WHILE while (
        #define DO ) {
        #define OD ;}
        #define INT int
        #define BEGIN {
        #define END }
        
        INT compare(s1, s2) STRING s1; STRING s2;
        BEGIN
            WHILE *s1++ == *s2
            DO IF *s2++ == 0
                THEN return(0)
                FI
            OD
                return (*--s1 - *s2);
        END
        
        /*翻译,原模原样替换就行*/
        int compare(s1, s2) char *s1; char *s2;
        {
            while (*s1++ == *s2 ) {
                if (*s2++ == 0) {
                    return (0);
                }
            ;}
            return (*--s1 - *s2);    
        } 

        相应的C代码: 
        int compare(s1, s2)
        char *s1, *s2;
        {
            while (*s1++ == *s2) {
                if (*s2++ == 0) return (0);
            }    
            return (*--s1 - *s2);
        } 
        /*Shell不使用malloc,而是使用sbrk自行负责堆存储的管理,Steve解释说,
         *他之所以采用这种特别的内存分配器,是为了提高字符串处理的效率
         */
        
        /*Bource创立的这种C语言变体事实上促成了异想天开的国际C语言混乱代码大赛
         *(The International Obfuscated C Code Competition)
         */

        宏最好只用于命名常量,并未一些适当的结构提供简捷的记法。宏名应该大写,这样便很容易
    与函数调用区分开来。千万不要使用C预处理器来修改语言的基础结构,因为这样一来C语言就不是C语言了。 

  • 相关阅读:
    硬件设计专题-DCDC电路起源
    java基础面试题:说说协程,进程和线程的区别和联系
    数据结构───顺序表(梦开始的地方)
    “薪资倒挂”、“毕业生平替” 这些现象说明测试行业已经...
    Linux操作系统~进程fork到wait到底怎么用?
    搭建简易Spring-ioc框架
    [云原生] 二进制安装K8S(中)部署网络插件和DNS
    Montreal Forced Aligner MFA
    Ubuntu 20.04 安装 SmartGit
    RabbitMQ可靠发布-SpringBoot
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126068072