精华内容
下载资源
问答
  • 在使用gcc编译的时候有时候会碰到这样的问题,编译为.o(obj) 文件没有问题,但是编译(这一步应该是链接)为可执行文件的时候会出现找不到’xxx’的定义的情况。 加上对应的库即可 ...

     

    在使用gcc编译的时候有时候会碰到这样的问题,编译为.o(obj) 文件没有问题,但是编译(这一步应该是链接)为可执行文件的时候会出现找不到’xxx’的定义的情况。

     

     

     

     

    加上对应的库即可

     

     

    现在还不太懂到底是什么意思 等以后学习了再回来看吧

     

    在此之前安装了libcap-dev  不知道有没有影响

     

    https://blog.csdn.net/haluoluo211/article/details/54376947

     

    展开全文
  • 定义 无声明 调用函数 可以编译,可以链接 有定义 有声明 调用函数 可编译,可链接 无定义 有声明 调用函数 可编译,无法链接 无定义 无声明 无法编译 二 静态断言 assert 宏定义: 1 用法和示例 在编写代码,...

    一 预处理:

    C语言是建立在适当的关键字,表达式,语句以及使用它的规则上。然而 ,C标准不仅描述C语言,还描述如何执行 C 预处理器,C标准库有那些函数,以及这些函数的工作原理。

    C 预处理器在程序执行之前检查程序(故称为预处理器),根据程序中的预处理器指令,预处理器把符号缩写替换成其表示的内容。预处理器可以包含程序所需要的其他文件,可以选择让编译器查看那些代码。预处理器并不知道 C 。基本上它的工作是把一些文本转换成另一些文本。看下面示例:

    #include<stdio.h> //包含头文件
    
    #define HW "hello word!"  //宏定义
    #define 开始执行  main     //宏定义
    //#就是预处理,编译器编译连接之前的处理
    
    int 开始执行()
    {
    	printf(HW);
    	getchar();
    }

    运行效果:

    1. 预处理:是指在进行编译之前所作的处理,由预处理程序负责完成
    2. 宏:用一个标识符来表示一个字符串,称为“宏”,被定义为“宏”的标识符称为“宏名”
    3. 宏替换:在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”

    这样简单的示例程序,都要经过编辑、预处理、编译、链接4个步骤,才能变成可执行程序,鼠标双击就弹出命令窗口,显示“Hello,World”。这也是一般C语言程序的编译流程。如下图:

    编辑可能就是通常所说的“写代码”,用集成开发工具也好,用记事本也好,按C语言的语法规则组织一系列的源文件,主要有两种形式,一种是.c文件,另一种是.h文件,也称头文件。

    1.1 预处理:

    “#include”和“#define”都属于编译预处理,C语言允许在程序中用预处理指令写一些命令行。预处理器在编译器之前根据指令更改程序文本。编译器看到的是预处理器修改过的代码文本,C语言的编译预处理功能主要包括宏定义、文件包含和条件编译3种。预处理器对宏进行替换,并将所包含的头文件整体插入源文件中,为后面要进行的编译做好准备。

    示例:

    // test.txt
    printf("你好,世界!\n");
    printf("你好,C 语言!\n");
    #include<stdio.h> //包含头文件 ,存放函数声明,让编译器直到有这个函数声明。
    
    // 连接,就是找到函数实体,让调用的函数能够成功执行。在本例中 printf 函数在 stdio.h 
    // 头文件中声明,所以要提前引入头文件,否则,无法执行打印输出。
    
    int main()
    {
    	#include"test.txt"; //包含文件
    	getchar();
    }

    1.2 编译:

    编译器处理的对象是由单个c文件和其中递归包含的头文件组成的编译单元,一般来说,头文件是不直接参加编译的。编译器会将每个编译单元翻译成同名的二进制代码文件,在DOS和Windows环境下,二进制代码文件的后缀名为.obj,在Unix环境下,其后缀名为.o,此时,二进制代码文件是零散的,还不是可执行二进制文件。错误检查大多是在编译阶段进行的,编译器主要进行语法分析,词法分析,产生目标代码并进行代码优化等处理。为全局变量和静态变量等分配内存,并检查函数是否已定义,如没有定义,是否有函数声明。函数声明通知编译器:该函数在本文件晚些时候定义,或者是在其他文件中定义。

     

    在 VS 中查看编译器:

    选中项目  右键【属性】 -->

    1.3 链接:

    链接器将编译得到的零散的二进制代码文件组合成二进制可执行文件,主要完成下述两个工作,一是解析其他文件中函数引用或其他引用,二是解析库函数。

    程序错误:

    编译链接,一大堆的错误提示,没有完美的程序,不存在没有缺陷的程序,如果一个程序运行很完美,那是因为它的缺陷到现在还没有被发现。同样,软件测试是为了发现程序中可能存在的问题,而不是证明程序没有错误。

    错误分类:

    1. 一是程序书写形式在某些方面不合C语言要求,称为语法错误,这种错误将会由编译器指明,是种比较容易修改的错误。
    2. 程序书写本身没错,编译链接能够完成,但输出结果与预期不符,或着执行着便崩溃掉,称为逻辑错误

    编译错误主要有两类:

    1. 语法问题,缺少符号,如缺分号,缺括号等,符号拼写不正确,一般来说,编译器都会指明错误所在行,但由于代码是彼此联系的,有时编译器给出的信息未必正确。
    2. 上下文关系有误,程序设计中有很多彼此关联的东西,比如变量要先创建再使用,有时编译器会发现某个变量尚未定义,便会提示出错。

    除了错误外,编译器还会对程序中一些不合理的用法进行警告(warning),尽管警告不耽误程序编译链接,但对警告信息不能掉以轻心,警告常常预示着隐藏很深的错误,特别是逻辑错误,应当仔细排查。

    有定义无声明调用函数可以编译,可以链接
    有定义有声明调用函数可编译,可链接
    无定义有声明调用函数可编译,无法链接
    无定义无声明 无法编译


    二 静态断言 assert  宏定义:

      1 用法和示例

    在编写代码时,我们总是会做一些假设,断言(assert)就是用于在代码中捕捉这些假设,可以看作是异常处理的高级形式。经常用于代码调试。

    可以在任何时候启用和禁用断言验证,因此可以在测试时启动断言,而在部署时禁用断言。

    示例:

    #define  _CRT_SECURE_NO_WARNINGS //宏定义,去掉安全检查
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h> //静态断言头文件
    
    
    void main()
    {
    	int n1, n2;
    	scanf("%d%d", &n1, &n2);
    	printf("n1=%d , n1=%d \n", n1, n2);
    
    	// 断言除数不能为0  ,n2 =0 不成立
    	assert(n2 != 0); 
    	double num = (double)n1 / n2;
    	printf("num=%f \n", num);
    
    
    	system("pause");
    }

    首选正常输入两个值进行计算:

    输入 0 引发错误,会弹出错误对话框。

     

    添加 宏定义:可以关闭静态断言

    #define NDEBUG   //关闭静态断言, 宏定义必须放在 引用头文件之前才有效

    示例2:

    #define  _CRT_SECURE_NO_WARNINGS //宏定义,去掉安全检查
    //#define NDEBUG   //关闭静态断言
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h> //静态断言头文件
    
    /* 静态断言,检测指针是否为空*/
    void main()
    {
    	char* p = (char*)malloc(sizeof(char) * 1024 * 1024 * 1024 * 10); //分配内存 10GB大小 ,验证报错
    	assert(p != NULL); //malloc 内存分配失败返回 NULL
    	*p = 'A'; //指针不为空时才能赋值
    	printf(*p);
    
    	system("pause");
    }

    如果不用 assert 静态断言,虽然程序错误,但是错误的产生原因和 错误发生的位置无法清晰定位。

    2:自定义 静态断言宏指令

    实现自定义的 assert 宏定义:

    #define  _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
    #include<Windows.h>
    
    #define DEBUG  //定义静态断言开启
    // x :是条件符号  \ :是链接符 #define一行写不下用 \ 连接   #x :会为 x 条件自动加上 "" 称为字符串
    
    #ifndef DEBUG  //如果有定义 ,使用 预编译指令,添加断言开关
    #define  myassert(x) //没有代码提示
    #else// DEBUG
    #define myassert(x)\
     if(!(x))\
    {\
    		printf("myassert(%s) 宏检测开始 ... ...\n", #x); \
    		printf("当前函数名:%s , 文件名和路径:%s ,代码行号:%d \n", __FUNCTION__, __FILE__, __LINE__);\
    		char errmsg[50];\
    		sprintf(errmsg,"当前函数名:%s , 文件名:%s ,代码行号:%d \n", __FUNCTION__, __FILE__, __LINE__);\
    		MessageBoxA(0,errmsg,"ERROR INFO:",0);\
    }
    #endif
    
    void main()
    {
    	int num = 10;
    	myassert(num < 10);
    
    	printf("num=%d \n", num);
    	system("pause");
    }

    输出:

    三 文件包含

    文件包含是 C 语言预处理的一个重要功能,用 "include" 来实现,将一个源文件的内容包含到另一个源文件中,称为它的一部分,文件包含的一般格式为:

       #include<文件名> 或者  #include"文件名"

    两种形式的区别在于:用尖括号表示在系统头文件目录中查找(由用户在编程环境中设置),而不在源文件目录中查找。使用双引号表示首先在当前源文件中查找,找不到再到系统头文件中查找。

    在 include"文件名" 格式下,用户可以显示地指名文件的位置:

    • #include"D:\A\1.c"
    • #include"..\x.c"  -- 上级目录下的 x.c 文件
    • #include".\x.c"  -- 当前级目录下的 x.c 文件
    • #include"\x.c"   -- 当前顶级目录下的 x.c 文件

    件包含语句中被包含的文件通常是以.h 结尾的头文件,这种头文件中的内容多为变量的定义、类型定义、宏定义、函数的定义或说明,但被包含的文件也可以是以.c为扩展名的C语言源文件。

    四  条件编译

    通过某些条件,控制源程序中的某段源代码是否参加编译,这就是条件编译的功能,一般来说,所有源文件中的代码都应参加编译,但有时候希望某部分代码不参加编译,应用条件编译可达到这以目的。

    条件编译的基本形式:

    NO .1:

    #if 判断表达式
        语句段1
    #else
         语句段2
    #endif

    示例:

    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>
    
    #define FLAG  1
    
    void main()
    {
    #if FLAG==2  //判断条件是否成立
    	MessageBoxA(0, "你好,世界!", "中文", 0);
    #else
    	MessageBoxA(0, "hello word!", "English", 0);
    #endif
    }

    效果:

    NO.2:

    #ifndef  标识符
    	语句段1
    #else
    	语句段2
    #endif
    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>
    
    #define FLAG  1
    
    
    
    void main()
    {
    #ifndef B //如果 B 每没有定义
    	MessageBoxA(0, "你好,世界!", "中文", 0);
    #else
    	MessageBoxA(0, "hello word!", "English", 0);
    #endif // !B
    
    }

    效果:

    C程序的编译分编辑、预处理、编译和链接几个步骤,预处理指令是由预处理器负责执行的,主要有头文件包含、宏定义、条件编译等,经过预处理后,编译器才开始工作,将每个编译单元编译成二进制代码文件,但此时分散的二进制代码文件中的变量和函数没有分配到具体内存地址,因而不能执行,需要链接器将这些二进制代码文件、用到的库文件中相关代码,系统相关的信息组合起来,形成二进制可执行文件。

    五 宏定义及其5个扩展

    5.1 扩展宏:

    除了常用的宏定义 #define 外,ANSI 标准说明了5个 常用于代码调试的 预定义宏指令:

    预定义宏指令
    _DATA_进行预处理的日期("Mmm dd yy" 形式的字符串)
    _FILE_代表当前源文件名的字符串
    _LINE_代表当前源代码中行号的整数常量
    _TIME_源文件编译的时间 ,格式:"hh:mm:ss"
    _FUNCTION_当前所在函数名

     

    常用方法在 上面 assert 断言 中已经使用过。这里再次举例:

    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>
    
    void show()
    {
    	printf("当前文件名称:%s\n", __FILE__);
    	printf("当前语句的行号: %d\n", __LINE__);
    	printf("当前函数名:%s\n", __FUNCTION__);
    	printf("当前编译日期:%s , 编译时间:%s\n", __DATE__, __TIME__);
    }
    
    
    
    void main()
    {
    	printf("当前文件名称:%s\n", __FILE__);
    	printf("当前语句的行号: %d\n", __LINE__);
    	printf("当前函数名:%s\n", __FUNCTION__);
    	printf("当前编译日期:%s , 编译时间:%s\n", __DATE__, __TIME__);
    
    	printf("\n------------------------------\n");
    	show();
    	system("pause");
    }

    效果:

     

    5.2 const常量与宏的差别:

    示例:

    #include<stdio.h>
    #include<stdlib.h>
    #include<Windows.h>
    
    
    #define X 12.5
    const int N = 12.5; //const 定义 存在 = 号赋值动作,会自动进行数据类型转换
    
    void main()
    {
    	printf("define 类型= %d\n", sizeof(X));
    	printf("const 类型= %d\n", sizeof(N));
    
    	system("pause");
    }

    输出:

    const 是有数据类型的,可以根据数据类型进行安全检查,发现类型不匹配时,会发出警告或转换,可以预防数据类型不匹配的错误。const 是伪常量,通过指针可以修改其值。#define 就是替换,没有数据类型,无法进行安全检查。#define 定义的常量是无法修改的,是真正意义的常量。

     

    5.3 宏的高级用法:

               # 与 ##  的用法

    1. # :宏给标识符加上 "" (双引号)。
    2. ## : 在 C语言宏中,被称为连接符(concatenator),它是一种预处理运算符,用来把两个语言符号(Token)组合成单个语言符号。语言符号不一定是 宏的变量,并且双#号不能作为第一个或最后一个存在。 ## 可以将两个记号"粘" 在一起,成为一个记号。

    示例:

    #include<stdio.h>
    #include<stdlib.h>
    
    #define  S(x) system(#x)
    #define PrintfNum(x) printf("%s=%d \n",#x,x);
    
    void main()
    {
    	int n1 = 10, n2 = 20, n3 = 30;
    	PrintfNum(n1);
    	PrintfNum(n2);
    	PrintfNum(n3);
    
    	S(calc); //参数名称没有加 "" 
    	S(notepad);//参数名称没有加 "" 
    
    }

    执行后打开了计算器和记事本 并且 输出了内容: 在 C 语言中 变量名实际上是对内存空间的抽象,不用 # 是无法把变量当字符串输出的。

    示例:

    #include<stdio.h>
    #include<stdlib.h>
    
    
    #define PrintfNum(x) printf("%s=%d \n",#x,x);
    #define N(x) N##x   //N 不要求是 宏的变量 任意值都可以
    #define P(x) show##x
    
    void show1()
    {
    	printf("NO 1\n");
    }
    
    void show2()
    {
    	printf("NO 2\n");
    }
    
    
    
    void main()
    {
    	int N(1) = 10, N(2) = 20, N(3) = 30;
    	N1 = 100; //## 是连接的作用 N(1) 等价于 N1
    	N2 = 200;
    	N3 = 300;
    	PrintfNum(N(1));
    	PrintfNum(N(2));
    	PrintfNum(N(3));
    
    	printf("\n----------------------------\n");
    	P(1)();  //当传入 1 时, show##x 等价于 将 show 和 1 连接在一起 组成函数名称
    	P(2)();
    
    	system("pause");
    }

    输出:

    六:预编译指令

    1:error:  在编译时输出编译错误信息,从而方便查看错误,进行调试

    #include<stdio.h>
    #include<stdlib.h>
    
    
    
    int main(void)
    {
    
    #define NAME1 "NAME1"
    	printf("%s \n", NAME1);
    #undef NAME1
    #ifndef NAME1
    #error No define NAME1
    #endif // !NAME1
    
    
    	return 0;
    }

    2: pragma message : 能够在编译窗口中输出相应的信息,对源代码的控制有用。

    #include<stdio.h>
    #include<stdlib.h>
    
    #pragma message("Copyright ©1995-2004 XXXXXX, Inc. All rights reserved.")//版权声明
    
    #define X64
    #ifdef X64
    #pragma message("不支持X64平台")
    #endif // X64
    
    
    int main(void)
    {
    
    	return 0;
    }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 从源代码生成可执行文件的各个阶段为: C源程序(.c)->编译预处理(.i)->编译(.s)->优化程序->汇编程序(.o)->链接程序->可执行文件(.exe) ...预处理过程在编译时处理包含其他源文件、定义宏、根据条

    从源代码生成可执行文件的各个阶段为:

    C源程序(.c)->编译预处理(.i)->编译(.s)->优化程序->汇编程序(.o)>链接程序->可执行文件(.exe)

      其中 编译预处理阶段,预处理器读取c源程序,进行初步的转换,即对其中的伪指令(以#开头的指令)和特殊符号进行处理后,翻译得到一个ASCII码的中间文件main.i交给编译器。预处理过程在编译时处理包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码等工作,还会删除程序中的注释和多余的空白字符。

    伪指令(或预处理指令)定义    

    预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。下面是部分预处理指令:

       指令         用途
        #           空指令,无任何效果
        #include    包含一个源代码文件
        #define     定义宏
        #undef      取消已定义的宏
        #if         如果给定条件为真,则编译下面代码
        #ifdef      如果宏已经定义,则编译下面代码
        #ifndef     如果宏没有定义,则编译下面代码
        #elif       如果前面的#if给定条件不为真,当前条件为真,则编译下面代码,其实就是else if的简写
        #endif      结束一个#if……#else条件编译块
        #error      停止编译并显示错误信息
    预处理指令主要包括以下四个方面:

    1、宏定义指令:#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。       

    2、条件编译指令:#if,#ifndef,#ifdef,#elif,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。

    3、头文件包含指令#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。

    4、特殊符号处理:可以识别一些特殊的符号。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。


    一、宏定义指令

      宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换成宏定义时的值。宏最常见的用法是定义代表某个值的全局符号。宏的第二种用法是定义带参数的宏(宏函数),这样的宏可以象函数一样被调用,但它是在调用语句处展开宏,并用调用时的实际参数来代替定义中的形式参数。

    1.1 #define指令
    1.1.1 #define预处理指令用来定义宏。该指令最简单的格式是:声明一个标识符,给出这个标识符代表的代码(比如像圆周率这样的数)。在后面的源代码中,我们就可以使用定义的宏取代要使用的代码,举例如下:

    #define MAX_NUM 10
    int array[MAX_NUM];
    for(i=0;i<MAX_NUM;i++) 

      在这个例子中,对于阅读该程序的人来说,符号MAX_NUM就有特定的含义,它代表的值给出了数组所能容纳的最大元素数目。程序中可以多次使用这个值。作为一种约定,习惯上总是全部用大写字母来定义宏,这样易于把程序的宏标识符和一般变量标识符区别开来。如果想要改变数组的大小,只需要更改宏定义并重新编译程序即可。

    1.1.2 使用宏的好处有两点:

    一是使用方便。如下:

    #define PAI 3.1415926
    PAI显然比3.1415926写着方便。

    二是定义的宏有了意义,可读性强。如例1,MAX_NUM,望文生意便知是最大数量的意思,比单纯使用10这个数字可读性要强的多。

    三是容易修改。如例1,如果在程序中有几十次会使用到MAX_NUM,修改只需要在宏定义里面修改一次就可以,否则你会修改到崩溃。

    1.1.3 宏表示的值可以是一个常量表达式,允许宏嵌套(必须在前面已定义)。例如:

    #define ONE 1
    #define TWO 2
    #define SUM(ONE+TWO)
    这里需要注意两点:
    一是注意上面的宏定义使用了括号。尽管它们并不是必须的。但出于谨慎考虑,还是应该加上括号的。例如:
                six=THREE*TWO;
        预处理过程把上面的一行代码转换成:
                six=(ONE+TWO)*TWO;
        如果没有那个括号,就转换成six=ONE+TWO*TWO;了。

    也就是说预处理仅是简单的字符替换,要时刻注意这一点,很多错误都会因此出现。

    二是虽然我们举例用了#define ONE 1 这个例子,但是一般要求宏定义要有其实际意义,#define ONE 1这种没意义的宏定义是不推荐的。(大概是这么个意思,忘记具体怎么说了)

    1.1.4 宏还可以代表一个字符串常量,例如:
                #define VERSION "Version 1.0 Copyright(c) 2003"

    1.2 带参数的#define指令(宏函数)
        带参数的宏和函数调用看起来有些相似。看一个例子:

    #define Cube(x) (x)*(x)*(x)

        可以时任何数字表达式甚至函数调用来代替参数x。这里再次提醒大家注意括号的使用。宏展开后完全包含在一对括号中,而且参数也包含在括号中,这样就保证了宏和参数的完整性。看一个用法:

    int num=8+2;
    volume=Cube(num);
      展开后为(8+2)*(8+2)*(8+2);
        如果没有那些括号就变为8+2*8+2*8+2了。
        下面的用法是不安全的:
                volume=Cube(num++);
        如果Cube是一个函数,上面的写法是可以理解的。但是,因为Cube是一个宏,所以 会产生副作用。这里的书写不是简单的表达式,它们将产生意想不到的结果。它们展开后是这样的:
                volume=(num++)*(num++)*(num++);
        很显然,结果是10*11*12,而不是10*10*10;
        那么怎样安全的使用Cube宏呢? 必须把可能产生副作用的操作移到宏调用的外面进行
                int num=8+2;
                volume=Cube(num);
                num++;

    宏函数使用不当会出现一些难以发现的错误,请慎重使用。

    几点注意:

    • 宏替换只是字符串和标识符之间的简单替换,预处理本身不做任何数据类型和合法性检查,也不分配内存单元
    • 宏定义时,形参通常要用括号括起来,否则容易导致逻辑错误。例如,如果定义:
          #define S(a,b) a*b/2
      那么程序中的S(3+5,4+2)就会被宏展开为3+5*4+2/2,不符合定义的真正的意图。
    • 带参宏定义形式上像定义函数,但它与函数的本质不同。宏定义只是产生字符串替代,不存在分配内存和参数传递。
    1.3 #运算符
        出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。有时把这种用法的#称为字符串化运算符。例如:

    #define PASTE(n) "adhfkj"#n
    int main()
    {
           printf("%s\n",PASTE(15));
           return 0;
    }
    //输出adhfj15
    宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。所以输出应该是adhfkj15。


    1.4 ##运算符(很少用)
        ##运算符用于把参数连接到一起。预处理程序把出现在##两侧的参数合并成一个符号。看下面的例子:

    #define NUM(a,b,c) a##b##c
    #define STR(a,b,c) a##b##c
    int main()
     {
           printf("%d\n",NUM(1,2,3));
           printf("%s\n",STR("aa","bb","cc"));
           return 0;
     }
    //最后程序的输出为:
    aabbcc
    二、条件编译指令

         程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。条件编译指令将决定那些代码被编译,而哪些是不被编译的。可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件。

    2.1 #if/#endif/#else/#elif指令
        #if指令检测跟在制造另关键字后的常量表达式。如果表达式为真,则编译后面的代码,知道出现#else、#elif或#endif为止;否则就不编译。
        #endif用于终止#if预处理指令。
        #else指令用于某个#if指令之后,当前面的#if指令的条件不为真时,就编译#else后面的代码。

    #define DEBUG       //此时#ifdef DEBUG为真
    //#define DEBUG 0  //此时为假
    int main()
    {
       #ifdef DEBUG
          printf("Debugging\n");
       #else
          printf("Not debugging\n");
       #endif
       printf("Running\n");
       return 0;
    }

    这样我们就可以实现debug功能,每次要输出调试信息前,只需要#ifdef DEBUG判断一次。不需要了就在文件开始定义#define DEBUG 0

    #elif预处理指令综合了#else和#if指令的作用。

    #define TWO
    int main()
    {
       #ifdef ONE
              printf("1\n");
       #elif defined TWO
              printf("2\n");
       #else
              printf("3\n");
       #endif
    }
    //输出结果是2。

    2.2 #ifdef和#ifndef

    这二者主要用于防止重复包含。我们一般在.h头文件前面加上这么一段:

    //funcA.h
    #ifndef FUNCA_H
    #define FUNCA_H
    //头文件内容
    #end if
    这样,如果a.h包含了funcA.h,b.h包含了a.h、funcA.h,假如不加上上面这么一段,则意味着重复包含funcA .h头文件,从而会出现一些type redefination之类的错误。
    #if defined等价于#ifdef; #if !defined等价于#ifndef

    三、头文件包含指令

    采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。

      #include预处理指令的作用是在指令处展开被包含的文件。包含可以是多重的,也就是说一个被包含的文件中还可以包含其他文件。标准C编译器至少支持八重嵌套包含。预处理过程不检查在转换单元中是否已经包含了某个文件并阻止对它的多次包含,这个的处理办法上面已经给出。

      在程序中包含头文件有两种格式:
            #include <my.h>
            #include "my.h"
       第一种方法是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种方法是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。
       采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。一个应用程序既包含编译器提供的公共头文件,也包含自定义的私有头文件。采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。

    四、特殊符号处理

    预编译程序可以识别一些特殊的符号。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

    4.1 __LINE__

    注意,是双下划线,而不是单下划线 。
    __FILE__ 包含当前程序文件名的字符串
    __LINE__  表示当前行号的整数
    __DATE__ 包含当前日期的字符串
    __STDC__  如果编译器遵循ANSI C标准,它就是个非零值
    __TIME__ 包含当前时间的字符串
    注意,是双下划线,而不是单下划线 。
    __FILE__ 包含当前程序文件名的字符串
    __LINE__  表示当前行号的整数
    __DATE__ 包含当前日期的字符串
    __STDC__  如果编译器遵循ANSI C标准,它就是个非零值
    __TIME__ 包含当前时间的字符串
    //例9
    #include<stdio.h>
    int main()
    {
       printf("Hello World!\n");
       printf("%s\n",__FILE__);//字符串形式输出该程序文件名(<span style="font-family:'Segoe UI', 'Microsoft YaHei', Georgia, Helvetica, Arial, sans-serif, 宋体, PMingLiU, serif;">含路径</span>)
       printf("%d\n",__LINE__);//输出<span style="font-family:'Segoe UI', 'Microsoft YaHei', Georgia, Helvetica, Arial, sans-serif, 宋体, PMingLiU, serif;">该行在<span style="font-family:'Segoe UI', 'Microsoft YaHei', Georgia, Helvetica, Arial, sans-serif, 宋体, PMingLiU, serif;">该文件中的行号</span></span>
       return 0;
    }

    4.2 #line等

    #error指令将使编译器显示一条错误信息,然后停止编译。
    #line指令改变_LINE_与_FILE_的内容,它们是在编译程序中预先定义的标识符。
    #pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。

    #line   100          //初始化行计数器 
    #include<stdio.h>    //行号100
    int main()
    {
        printf("Hello World!\n");
        printf("%d",__LINE__);
        return 0;
    }
    //输出104


    总结:预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。





    展开全文
  • 编译时显示xml_document xml_node等为未声明的标识符,但是可以声明F12可以转到定义。 问题原因:未使用 pugi:: 命名空间 解决方法:使用 pugi::xml_document pugi::xml_node,或在文件前加上using namespace ...

    问题描述:使用了pugixml库,包含了头文件。编译时显示xml_document  xml_node等为未声明的标识符,但是可以声明F12可以转到定义。

    问题原因:未使用 pugi:: 命名空间

    解决方法:使用 pugi::xml_document  pugi::xml_node,或在文件前加上using namespace pugi;

    展开全文
  • C语言中的预编译定义

    千次阅读 2015-01-14 16:25:16
    在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译器处理之前, 预处理器首先对源程序中的"宏(macro)"进行处理.  C初学者可能对预...
  • 有时候我们在cube创建工程后会添加一些自己定义的配置,如果我们没有在cube中设置如定时器,而我们自己添加文件却用到了定时器,这时候编译一下你会发现头文件明明已经加进去了,却仍显示未定义,这时候只要在config...
  • 编译错误类型: 必须定义入口点

    万次阅读 多人点赞 2016-05-12 11:06:39
    # 经常有同学写完程序编译时会发现有这样的错误: LINK : fatal error LNK1561: 必须定义入口点; # 我发现有这样两种情况下会发生这样的错误(都是自己犯过的); @ 主函数 int main() 写成了 int mian...
  • Texstudio编译latex参考文献、成果等无法显示 第一步,在谷歌学术上copy到bib类型引用 粘贴到根目录的Reference.bib文件中 按下F8编译reference.bib文件,(那是不可能的!) 先编译main.tex,会生成一个.aux文件...
  • 使用cmake生成makefile,编译时,出现redefine main 的错误提示,该提示是由于在工程中,出现了两个或者以上的main函数, 多由写测试程序,程序中包含了main函数,然后在搬进开发的工程中,忘了注释掉main函数,...
  •  最近在编译TVOS2.1代码编译9分钟后提示一个枚举变量没有定义:  查看DTVAL.h文件,此文件有声明一个函数,函数第二个参数有使用到一个枚举变量,提示没有定义。然后查看原因,DTVAL.h文件有包含DTVALDATA....
  • C中的预编译定义

    千次阅读 2017-06-25 11:28:58
    C中的预编译定义   2009-02-10 作者: infobillows 来源:网络   在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流...
  • 看一个异常是运行还是编译时异常,最简单的方法是看他的父类或者看他的爷爷、太爷爷...(开个玩笑)是不是RuntimeException。 比较通俗易懂的方法是,你把代码写出来之后,有红色波浪线提示你抛出或捕获异常,这...
  • 编译时与运行 编译时: 即编译器对语言的编译阶段,编译时只是对语言进行最基本的检查报错,包括词法分析、语法分析等等,将程序代码翻译成计算机能够识别的语言(例如汇编等),编译通过并不意味着程序就可以成功...
  • 我用cmake编译出lzo源码的vs工程文件,通过vs2015打开lzo.sin工程文件并生成,生成的时候报错: C1189 #error: Macro definition of snprintf conflicts with Standard Library function declaration 错误文件显示...
  • 你在添加文件没有选中...CodeBlocks在构建程序以Targets为单位,若你没有把文件添加到指定Target,那么构建该Target将不会编译该文件。在新建文件会提示文件名,同时也有Targets选择,你必须勾选两个Target
  • 编译时多态与运行多态的区别

    千次阅读 2018-03-24 10:48:32
    (1)编译时多态/静态联编 指联编工作在编译阶段完成,即在编译阶段确定了程序中的操作调用与执行该操作的代码间的关系,基于指向对象的指针类型或引用类型。 (2)运行多态/动态联编 指联编在程序运行动态进行...
  • ###编译中重定义错误的处理 在编译代码的时候会有各种各样的错误,本文主要说下重定义的错误处理。这个大家应该都遇见过,无非就是变量或者函数定义重复了啊,对,简单来说就是这样的,经常出现先复制变量或者代码...
  • make编译高亮显示错误、警告等信息

    千次阅读 2020-07-05 14:56:56
    原因:今天编译gcc源码,出现错误,但是编译信息太长了,无法找到错误在哪里;还好GitHub上有 color_cpmpile 项目,真是造福啊!感谢此项目的原作者!以及这位博客! github的color_cpmpile项目 1.第一不: git ...
  • Gcc 编译时指定宏

    千次阅读 2017-01-04 19:19:12
    这样就定义了预处理宏,编译的时候可选代码就会被编译进去了。 举例说明: -Dmacro=string,等价于在头文件中定义:#define macro string。 -DTRUE=true,等价于在头文件中定义:#define TRU
  • DELPHI定义的条件编译的全部说明

    千次阅读 2016-12-01 22:25:58
    可是这些好像并没有定义,不知道在哪里可以找到这些条件编译定义或者是说明具体讲述win16代表什么,WIN32代表什么,VER140。。。。代表什么的? {$IFDEF WIN32} — 这可不是批注 对于Delphi来说﹐左右大括号...
  • 1、确认应用的文件是否有编译,测试方法修改错文件中的内容再次编译看是否报错 2、如果没有说明没有参与编译,需要修改makefile文件添加编译对应文件生成.o目标文件。 3、如果发现已经添加了该文件,还有一种可能...
  • gcc, g++编译时消除特定警告的方法

    万次阅读 2018-04-24 11:14:41
    gcc 编译器为我们提供了很多的编译选项:-Wall 会打开一些很有用的警告选项,建议编译时加此选项。具体如下: -Waddress -Warray-bounds (only with -O2) -Wc++0x-compat -Wchar-subscripts -Wimplicit...
  • 关于C的预编译定义 的一些使用

    千次阅读 2014-05-26 12:59:41
    根据#define 和条件编译 #ifdef、#ifndef #else #endif 最经常的使用是 头文件 防止重复包含。 但是 使用 #pragma once 更好,现在 gcc cl.exe 都支持,它不但代码更少,而且不用为宏起名字,更好。 ...
  • gcc编译时对’xxxx’未定义的引用...在使用gcc编译的时候有时候会碰到这样的问题,编译为.o(obj) 文件没有问题,但是编译(这一步应该是链接)为可执行文件的时候会出现找不到’xxx’的定义的情况。 本文由乌
  • ”——顺手删了,没关心宏定义,主要是添加头文件,编译成功。 当时以为只是画蛇添足,删不删就是个习惯,对结果影响不大,没想到会是错误源头。     到了客户端,出现了编译错误。   expected ‘)’ ...
  • 程序设计中的预处理(Preprocess),程序设计领域,预处理是在程序源代码被编译之前,由预处理器(Preprocessor)对程序源代码进行的处理。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的符号...
  • 程序编译时提示undefined symbol

    千次阅读 2019-01-10 17:05:14
    编译程序提示如下图: Error:L6218E: Undefined symbol xxxxx 意思为:Rs485_send_buf这个数组没有定义就使用了。 实际上在头文件已经定义了,并且该头文件也被调用了,程序如下: extern void Rs485_send_buf[8...
  • 造成该问题的可能性比较多,本人将在今后遇到添加进来,今天先放出本人遇到的一种情况。  多重包含含有变量定义的.h文件所造成  这个现象很容易重新,首先新建一个1.h文件,然后在里面写下如下代码 #pragma once...
  • #include using namespace std; void str(const char *p, int n); int main() { ..... str(pstr); ...void str(const char *p,...我定义了一个函数,在主函数前对它声明,在主函数中调用,运行时显示“str”: 函数不接受 1

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 558,018
精华内容 223,207
关键字:

编译时显示重新定义