《朱老师物联网大讲堂》学习笔记
学习地址:www.zhulaoshi.org
(1).
源代码.c,预处理过的.i文件,汇编文件.s,目标文件.o,可执行程序.elf,
预处理器,编译器,汇编器,链接器,这些工具合起来就叫做编译工具链,
gcc中只预处理不编译的方法,gcc -E xx.c -o xx,
只编译不连接,gcc xx.c -o xx,
(2).
#include<xx.h>,
只到系统指定目录去找头文件,
#include"xx.h",
首先找当前目录,然后找系统目录,
编译-I参数包含头文件所在文件夹,#include<xx.h>,
条件编译,
#define NUM //有这句话,a=111,没有a=222,
int a;
#ifdef NUM
a=111;
#else
a=222;
#endif
#ifdef和#if的区别是,前者判断符号存在与否,后者判断逻辑真假,
(3)~(4).
宏定义,原封不动的替换,
#define X(a,b) a+b
int x=1,y=2;
int c = X(x,y); //替换后为int c = 1 + 2;
#define X(a,b) a+b
int x = 1, y = 2;
int c = 3*X(x,y); //替换后的结果为int c = 3*1+2; 大失所望吧~
//所以最好是每个都加括号,#define X(a,b) ((a)+(b))
#define MAX(a,b) ((a)>(b)?(a):(b))//比较两个数的大小,
#define SEC_PER_YEAR (365*24*60*60UL) //这里的难点是,数字默认int,而这里的这个数字超过了int的范围,所以需要声明为无符号数
像MAX(a,b),使用起来已经看不出来是不是函数了,
宏定义是在预处理期间原地展开的,
而函数是在编译期间处理的,是通过调用实现的,调用会有相应的开销,
函数相对于宏定义有参数检查,返回值类型检查,
内联函数,是宏和函数的结合,有参数检查,同时不用调用开销,能原地展开,
debug版本和release版本,
#define DEBUG
//#undef DEBUG
#ifdef DEBUG
#define debug(x) printf(x)
#else
#define debug(x)
#endif
(5).
传参不要太多,
少用全局变量,
(6).
函数名表示了这个函数在内存中的地址,用函数名来调用执行函数,实质就是指针解引用访问,
(7).
用递归函数来计算阶层,
int jiecheng(int n)
{
if( n<1 )
{
return -1;
}
if( 1==n )
{
return 1;
}
else
{
return (n*jiecheng(n-1));
}
}
(8).
.o目标文件,
.a静态链接库文件,
有些库函数链接时需要额外用-lxxx来指定链接,
如果是动态库,要注意-L指定动态库的地址,
(9).
字符串函数,
字符串处理的需求是客观的,
string.h在/usr/include中,
(10).
数学库函数,
真正的数学运算的函数定义在:/usr/include/i386-linux-gnu/bits/mathcalls.h,
(11).
自己制作静态链接库并使用,
使用-c选项,只编译不链接,
使用ar工具生成归档文件,其文件后缀是.a
静态库文件名字,一般是lib+库名,注意后面使用的时候lib不算库名部分,
all:
gcc aston.c -o aston.o -c
ar -rc libaston.a aston.o
把.a和.h都放在我引用的文件夹下,然后在.c文件中包含库的.h,然后直接使用库函数。
第一次,编译方法:gcc test.c -o test
报错信息:test.c:(.text+0xa): undefined reference to `func1'
test.c:(.text+0x1e): undefined reference to `func2'
第二次,编译方法:gcc test.c -o test -laston
报错信息:/usr/bin/ld: cannot find -laston
collect2: error: ld returned 1 exit status
第三次,编译方法:gcc test.c -o test -laston -L.
无报错,生成test,执行正确。
这么多不是亲生的文字,肯定头大,
我来简单说下,第一种是没有去找,第二种是找不到,
-laston 用来指明链接的库,
-L. 用来指明链接的位置,即库在哪里,注意后面有个点啊,代表当前目录,
使用nm命令查看有哪些符号,
(12).
自己制作动态链接库并使用,
这里的动态库后缀是.so
而不是.dll
all:
gcc aston.c -o aston.o -c -fPIC
gcc -o libaston.so aston.o -shared
其中-fPIC的意思是位置无关码,
-shared意思是按照共享库的方式来链接,就是动态库,
给别人使用发布.so和.h即可,
接下来是使用,
按照静态库的方式来使用,看会出什么错误,
编译方法:gcc test.c -o test -laston -L.
编译成功
但是运行出错,报错信息:
error while loading shared libraries: libaston.so: cannot open shared object file: No such file or directory
错误原因:动态链接库运行时需要被加载(运行时环境在执行test程序的时候发现他动态链接了libaston.so,于是乎会去固定目录尝试加载libaston.so,如果加载失败则会打印以上错误信息。)
解决方法一:
将libaston.so放到固定目录下就可以了,这个固定目录一般是/usr/lib目录。
cp libaston.so /usr/lib即可
解决方法二:使用环境变量LD_LIBRARY_PATH。操作系统在加载固定目录/usr/lib之前,会先去LD_LIBRARY_PATH这个环境变量所指定的目录下去寻找,如果找到就不用去/usr/lib下面找了,如果没找到再去/usr/lib下面找。所以解决方案就是将libaston.so所在的目录导出到环境变量LD_LIBRARY_PATH中即可。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/mnt/hgfs/Winshare/s5pv210/AdvancedC/4.6.PreprocessFunction/4.6.12.sharedobject.c/sotest
在ubuntu中还有个解决方案三,用ldconfig
(4)ldd命令:作用是可以在一个使用了共享库的程序执行之前解析出这个程序使用了哪些共享库,并且查看这些共享库是否能被找到,能被解析(决定这个程序是否能正确执行)。
ps:若是找不到,会有提示。