JNI入门之C/C++基础六

1.6预编译指令

1.6.1 C语言执行的流程

编译:形成目标代码(.obj)

连接:将目标代码与C函数库连接合并,形成最终的可执行文件

执行

1.6.2预编译

预编译(预处理),为编译做准备工作,完成代码文本的替换工作

1.6.3宏定义、宏替换、预编译指令

#include命令

#include是文件包含命令,主要用来引入对应的头文件。#include的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。

代码示例:

 

//自定义的.h头文件

printf("%s\n","haha");

 

//带main函数的.c文件

#include <stdio.h>

#include <stdlib.h>

 

void main() {

         #include "my.h"

         getchar();

}

 

上面的例子输出: haha

#include "my.h"相当于把my.h中的代码复制一份

 

#define  

定义一个预处理宏

宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。

宏定义的一般形式为:

#define  宏名  字符串

 

#include <stdio.h>

#define N 100

 

int main(){

    int sum = 20 + N;

    printf("%d\n", sum);

    return 0;

}

运行结果:120

 

程序中反复使用的表达式就可以使用宏定义,例如: #define M (n*n+3*n)

它的作用是指定标识符M来代替表达式(n*n+3*n)。在编写源程序时,所有的(n*n+3*n)都可由M代替,而对源程序编译时,将先由预处理程序进行宏代换,即用(n*n+3*n)表达式去替换所有的宏名M,然后再进行编译。

将上面的例子补充完整:

#include <stdio.h>

 

#define M (n*n+3*n)

 

int main(){

    int sum, n;

    printf("Input a number: ");

    scanf("%d", &n);

    sum = 3*M+4*M+5*M;

    printf("sum=%d\n", sum);

    return 0;

}

 

 

运行结果:
Input a number: 10↙
sum=1560

上面的程序中首先进行宏定义,定义M来替代表达式(n*n+3*n),在sum=3*M+4*M+5*M中作了宏调用。在预处理时经宏展开后该语句变为:

sum=3*(n*n+3*n)+4*(n*n+3*n)+5*(n*n+3*n);

需要注意的是,在宏定义中表达式(n*n+3*n)两边的括号不能少,否则会发生错误。如当作以下定义后:

#difine M n*n+3*n

在宏展开时将得到下述语句:

s=3*n*n+3*n+4*n*n+3*n+5*n*n+3*n;

这相当于:

3n2+3n+4n2+3n+5n2+3n

这显然是不正确的。所以进行宏定义时要注意,应该保证在宏代换之后不发生错误。

注意事项:

1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的替换。字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。

2) 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。

3) 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。

#define PI 3.14159

 

int main(){

    // Code

    return 0;

}

 

#undef PI

 

void func(){

    // Code

}

 

表示PI只在main函数中有效,在func中无效。

 

4) 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换,例如:

#include <stdio.h>

#define OK 100

int main(){

    printf("OK\n");

    return 0;

}

 

运行结果:OK

 

5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。例如:

#define PI 3.1415926

#define S PI*y*y    /* PI是已定义的宏名*/

 

int main(){

         int y = 2;

         printf("%f", S);

         getchar();

         return 0;

}

6) 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。

7) 可用宏定义表示数据类型,使书写方便。例如:

#define UINT unsigned int

在程序中可用UINT作变量说明:

UINT a, b;

应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串代换,是在预处理完成的,typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。

请看下面的例子:

#define PIN1 int *

typedef (int *) PIN2;

从形式上看这两者相似,但在实际使用中却不相同。
下面用PIN1,PIN2说明变量时就可以看出它们的区别:

PIN1 a,b;

在宏代换后变成:

int *a,b;

表示a是指向整型的指针变量,而b是整型变量。然而:

PIN2 a,b;

表示a、b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型,但毕竟是作字符代换。在使用时要分外小心,以避出错。

宏函数:

##是连接符号

#define jni(NAME) com_zl_jni_##NAME()

void com_zl_jni_write() {

         printf("write\n");

}

void com_zl_jni_read() {

         printf("read\n");

}

void main() {

         jni(write);     //相当于com_zl_jni_write();

         jni(read);     //相当于com_zl_jni_read();

         getchar();

}

输出结果:

write

read

下面是更灵活的用法:

#define LOG(LEVEL,FORMAT,...) printf(##LEVEL); printf(##FORMAT,__VA_ARGS__);

#define LOG_I(FORMAT,...) LOG("INFO:",##FORMAT,__VA_ARGS__);

#define LOG_E(FORMAT,...) LOG("ERROR:",##FORMAT,__VA_ARGS__);

#define LOG_W(FORMAT,...) LOG("WARN:",##FORMAT,__VA_ARGS__);

 

#ifndef

头件的中的#ifndef,为了解决引用头文件冲突的问题

下面一个例子,a.h和b.h相互引用,会发生冲突,可采用#ifndef去判断是否定义了当前头文件, AH是一个“标识”,是自由命名,但为了程序可读性,一般用头文件名大写

 

a.h  头文件

//如果没有定义AH,定义AH

#ifndef AH

#define AH

#include "b.h"

void say_a();

#endif

 

b.h  头文件

//如果没有定义BH,定义BH

#ifndef BH

#define BH

#include "a.h"

void say_b();

#endif

 

带主函数的 .c文件

#include "a.h"

 

void say_a(){

         printf("print A");

}

 

void main() {

         say_a();

         getchar();

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值