c语言写预处理器,C语言预处理器详解

1.预定义符号

下面这些是C语言的预处理器定义的符号,他们都是常量十进制数,或者是常量字符串。他们用来指示调试输出来源以及为编译程序加如时间信息。而STDC用来进行条件编译。其详细意义如下:

FILE:表示进行编译的源文件名

LINE:当前行在源文件中的行数

DATE:编译时候的日期

TIME:编译时候的时间

STDC:如果编译器遵循ANSI C 那么这个值就是1,否则未定义。

2. #define

2.1 #define 替换

在程序中我们可以使用#define来进行对源程序在预处理时期的替换。

最最常见的有:

#define uint unsigned int

#define uchar unsigned char

这样可以免去敲冗长的类型名,在预处理阶段所有的 uint 和 uchar 都会被分别替换为 unsigned int 和 unsigned char 。

注意:遇到上面这样的情况,最佳的选择是使用typedef来创建别名,而不是使用宏替换。

typedef unsigned int uint;

typedef unsigned char uchar;

2.2 #define 与 函数

有时候我们采用宏来充当函数,采用#define的一个好处是,对于简短的函数段,可以直接插入在程序中,而若使用函数的话会在调用函数时产生堆栈上的开销。其次有些时候,参数类型不明确所以用函数实现不够方便。

如:

#define MAX(x,y) ( (x) > (y) ? (x) : (y))

这个定义能够求出最大值,作用类型可以使任何能够用>比较的类型。

##用来连接两个符号,举例如下:

#define ADD_NO(number) NO##number

这样 ADD_NO(1),将得到NO1,需要注意的是,你一定要确保在程序中,你定义了NO1这个变量。

#argument 被用来指代宏参数对应的字符串,下面一个例子能让你明白:

#define PRINT_INT(x) printf(“The value of” #x “is:%d\n”,x)

调用:

int a=3;

PRINT_INT(a+10);

结果为:

The value of a+10 is:3

2.3 副作用

副作用 1

观察上面的定义,每一个字符都用括号括起来了,这是因为,宏并不求值而只是简单的替换,带参数的宏定义也如此。

如果写成下面这样:

#define MAX(x,y) x > y ? x : y

在程序中假如有这样的语句:

int a=MAX(1+2,2+3);

展开后得到:

int a=1+2>2+3?1+2:2+3;

这可能不是我们想要的结果。

所以记住一点,它只是替换,并不求值。

副作用 2

在考虑上面的MAX宏,我们用下面的方式调用:

c=MAX(a++,b++);

我们希望他像函数一样,在比较完大小后,a和b的值都能加1.但是我们展开后得到:

c=((a++)>(b++)?(a++):(b++));

显然,较大的那个变量将自加两次,这显然不是我们所渴望的。所以我们一定要注意自己调用的函数是不是真的是一个函数,因为我们无法成外观上区分他们到底本质上是不是一个宏。如getchar() 它就是一个宏

副作用 3

有时候,因为宏而产生的错误是很隐蔽的,让你难以发现,考虑:

#define PRINT_TWICE(ch) putchar(ch);putchar(ch)

我们希望这个定义能够帮我们打印一个字符两次,当我们用下面这样的方法调用时:

PRINT_TWICE(fgetc(fp));

从文件中读取一个字符,然后打印两次。但是上,他从文件中读取了两次取得两个字符,然后输入到标准输出。

综上,当在使用宏的时候,一定要警惕,它是否会产生上面提到的这类不易察觉的副作用。其次为了区别宏与函数,通常用全部大写字母来为宏命名。

2.4 #undef

当我们需要在重新定义一个宏,或者要移除一个宏的时候,可以使用下面这样的形式:

#undef name

2.5 分号加不加?

当我们用宏定义了一条完整的语句的时候,我们可能希望给它后面加上一个分号,这可能不会产生大的问题。其实我们在使用了宏以后习惯性的会在其后面加上一个分号,向普通的语句一样。永远记住宏做的工作是替换,你在定义它的时候在其后加了分号,那么在调用的时候就可以不用加分号了。如过你加了那么一个分号将产生一条空语句。

虽然一条空语句可能不会影响到程序的执行,你也不会察觉,但是有时候它可能会导致发生错误,举例如下:

#define PRINT(x) putchar(x);

if(...)

PRINT(x);

else

...

这仅仅是由于if语句因为下面只有一条语句所以没有加花括号,但是这个宏实际上是两条语句。当然这个问题可以在if后加上花括号来解决。

3. 条件编译

有的时候,程序会更具编译环境来有逻辑的进行编译,举例如下:

#define DEBUG 1

#if DEBUG

打印变量的值,程序的状态等

#endif

当我们在调试程序的时候,我们可以将DEBUG设置为1,但调试完毕后将他改为0,这样我们不必去删除分布于源文件中各个地方的打印状态的语句了。

条件编译提供了以下关键字:

#if,#elif,#else,#endif,#ifdef,#ifndef

其中前四个意义明确,没错就是你理解的那样,#elif 的意思就是else if。而#ifdef name是说如果定义了name,#ifndef name 是说如果没有定义name。

还有define(…)它的意义如下:

#if defined(…) 同 #idef …

#if !define(…) 同 #ifndef

4. 文件包含

当我们的程序需要依赖于起来的头文件的时候,我们使用#include 这样的指令将源文件包含进来,就像用被包含的文件的内容替换掉#include 这句话一样。

使用尖括号是说明被包含的文件是库文件,它的路径由编译器的配置决定。使用#include "filename"这样的用双引号包围的形式,是说该文件不是库文件,它的路径引号内路径决定。如#include "cv/cv.h"是说包含当前目录下cv文件夹中的cv.h文件。

当工程很大的时候,文件互相包含,这个时候会出现同一个文件被嵌套包含多次的情况,为了避免这种情况,我们在定义头文件时,常常像下面这样写:

#ifndef __SPEACIAL_H_

#define __SPEACIAL_H_

//在这里写文件内容

#endif

每个头文件在被预处理的时候,都会定义一个特殊的宏。如果相同的头文件再次出现的时候,由于在#ifndef这里将为假,所以忽略里面的内容。

5. 其他指令

5.1 #error

#error error message

当处理到上面这条指令的时候,会出现错误信息。

5.2 #line

#line number “filename”

这个指令后面可以跟两个常量,前面一个是数字是必须有的,后面的字符串可有可无。前面的number将会修改LINE,它指明下一行的行号是number,而后面的字符串会修改FILENAME,即文件名。

5.3 #progma

这个指令因编译器不同而不同,它用来支持因编译器而异的特性。

6. 结语

预编译预指令不常用到,但是还有有必要了解,今天把处理器就介绍到这里,如有任何错误还望各位指出。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在修改 Element UI 组件时,如果想要仅当前页面生效,可以使用 scoped CSS。 Scoped CSS 是 CSS 的一种特性,它允许你为当前作用域定义的 CSS 样式只对当前组件生效。 在 Element UI 的组件使用 scoped CSS,你只需要在该组件的 style 标签加入 scoped 属性即可。例如: ``` <template> <!-- 组件模板 --> </template> <style scoped> /* 这里定义的 CSS 样式只对当前组件生效 */ </style> ``` 这样你就可以在当前组件修改 Element UI 的样式,而不影响到其他组件。 ### 回答2: 要修改 ElementUI 仅当前页面生效,可以使用以下两种方法: 1. 自定义主题: 需要在当前页面创建一个独立的自定义主题,在该主题修改 ElementUI 的样式。可以使用 ElementUI 提供的主题配置文件 `element-variables.scss` 进行修改,或者使用 `less` 或 `sass` 等预处理来自定义样式。 在当前页面的样式文件引入自定义主题文件,并使用 `@import` 导入 ElementUI 的样式文件,确保自定义样式在 ElementUI 样式之后生效。 2. 使用 scoped 样式: 在当前页面的样式文件,给所有 ElementUI 的组件的容元素加上 `scoped` 属性,这样样式只会在当前页面的组件范围内生效,不会影响其他页面的样式。 使用 scoped 样式时,需要注意使用 `/deep/` 或者 `>>>` 符号来修改 ElementUI 组件内部的样式。例如: ```html <style scoped> .element-button >>> .el-button { /* 修改按钮的样式 */ } </style> ``` 这样只会将当前页面的按钮样式修改为指定样式,其他页面的按钮样式不会受到影响。 以上两种方法都可以实现 ElementUI 仅当前页面生效的效果,选择合适的方法根据实际需求来决定。 ### 回答3: 要使修改的element-ui仅在当前页面生效,可以按照以下步骤操作: 1. 在你的项目找到引入element-ui的地方,通常是在`main.js`或者你当前页面的入口文件引入。 2. 在引入element-ui之前,先引入一个单独的自定义样式文件,例如`custom-elementui.css`。 3. 在`custom-elementui.css`文件,根据你需要修改的element-ui组件的类名或选择进行样式修改。例如,如果你想修改按钮的背景颜色,可以添加以下代码: ```css .el-button { background-color: red; } ``` 4. 在`main.js`(或者你的入口文件),通过`import`将`custom-elementui.css`导入。确保它在element-ui的导入之前被导入。示例代码如下: ```javascript import Vue from 'vue'; import App from './App.vue'; import './custom-elementui.css'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); new Vue({ el: '#app', render: h => h(App) }); ``` 这样配置之后,`custom-elementui.css`的样式修改将仅在当前页面生效。其他页面引入element-ui时不会受到影响。 需要注意的是,这种方法只适用于修改element-ui组件的默认样式。如果需要修改更为复杂的功能或组件行为,可能需要进一步的定制化操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值