C语言学习 — 符号以及编译过程
一、一些符号
反斜杠
C语言的转义字符(\)主要用于标识无回显字符,也可用于表示常规字符
#include <stdio.h>
int main()
{
char enter = '\n'; // 换行
char* p = "\141\t\x62"; // \转义字符 将8进制的 141 转成10进制就是 97 然后\t为 tab 按键 16进制的62 就是 98
printf("%s",p);
printf("%c",enter);
return 0;
}
- C语言中的反斜杠(\)同时具有 接续符 和 转义符 的作用
- 作为接续符使用时可直接出现在程序中
- 作为 转义符 使用时需出现在 单引号或双引号 之间
单引号和双引号
-
C语言中的 单引号 用来表示 字符字面量
字符字面量 被 编译为 对应的 ASCII码
-
单引号括起来的单个字符代表 整数
-
C语言中的 双引号 用来表示 字符串字面量
字符串字面量 被 编译为 对应的 内存地址
-
双引号括起来的字符代表 字符指针
-
‘a’ 表示 字符 字面量
在内存中占一个字节
‘a’ + 1 表示 ‘a’ 的ASCII码加1,结果为 ‘b’ -
“a” 表示 字符串 字面量
在内存中占2个字节
“a” + 1 表示 指针运算,结果指向 “a” 结束符 ‘\0’ -
printf 的第一个参数被当成字符串内存地址
-
内存的低地址空间不能再程序中随意访问
#include <stdio.h>
int main()
{
char c = " ";//c一个字节,后面的是一个地址值4个字节,赋值给c会产生截断
while((c == "\t") || (c == " ") || (c == "\n"))//双引号中的值编译过后是一个地址值
{
scanf("%c",&c);
}
return 0;
}
分析上面的例子:
char c = “string”;
- 编译后字符串 “string” 的内存地址被赋值给变量 c;
- 内存地址占用 4个字节,而变量 c只占用一个字节;
- 由于类型不同,赋值后产生截断。
所以上面的例子,while语句一次也不会执行。
所以上面的例子,正确的是把所有的双引号变成单引号;变量c和单引号内对应字符的 ASCII码进行比较,变量c本身赋值为空格键的 ASCII码对应的值。
二、编译过程
预编译(预处理器)
-
处理所有的注释,以空格代替
-
将所有的 #define 删除,并且展开所有的宏定义
-
处理条件编译指令 #if, #ifdef, #elif, #else, #endif
-
处理 #include, 展开被包含的文件
-
保留编译期需要使用的 #pragma指令
-
预处理指令示例:
gcc -E file.c -o file.i
编译(编译器)
对预处理文件进行词法分析,语法分析和语义分析
- 语法分析:分析关键字,标识符,立即数等是否合法
- 语法分析:分析表达式是否遵循语法规则
- 语义分析:在语法分析的基础上进一步分析表达式是否合法
分析借宿后进行 代码优化 生成相应的 汇编代码文件
- 编译指令示例:
gcc -S file.c -o file.s
汇编
- 汇编器将汇编代码转变为机器的可执行指令
- 每条汇编语句几乎都对应一条机器指令
- 汇编指令示例:
gcc -c file.c -o file.o
链接
链接是指 将目标文件最终链接为可执行程序
- 静态链接:目标文件 直接连接进入可执行程序(小工程项目常用方式)
- 动态连接:在程序 启动后在动态加载目标文件(大型软件系统,方便更新局部功能,使用很多动态库,然后更新的时候,只需要更新相应的库文件,程序运行过程中加载的库文件)
动态库使用示例:
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void* pdlib = dlopen("./dlib.so", RTLD_LAZY);
char* (*pname)();
int (*padd)(int, int);
if(pdlib != NULL)
{
pname = dlsym(pdlib,"name");
padd = dlsym(pdlib,"add");
if((pname != NULL) && (padd != NULL))
{
printf("Name: %s\n",pname());
printf("Result: %s\n",padd(2, 3));
}
dlclose(pdlib);
}
else
{
printf("Cannot open lib ...\n");
}
}
- 点赞
- 收藏
- 关注作者
评论(0)