215做网站,wordpress注明网站,施工企业财务经理年终总结,网站提示宏文章目录 1.编译预处理#xff1a;C源程序 - 编译预处理【#开头指令和特殊符号进行处理#xff0c;删除程序中注释和多余空白行】- 编译2.gdb调试#xff1a;多进/线程中无法用3.makefile文件#xff1a;make是一个解释makefile中指令的命令工具4.文件#xff1a;fprint/f… 文章目录 1.编译预处理C源程序 - 编译预处理【#开头指令和特殊符号进行处理删除程序中注释和多余空白行】- 编译2.gdb调试多进/线程中无法用3.makefile文件make是一个解释makefile中指令的命令工具4.文件fprint/fgets/fwrite/freadftell/rewind/fseek/fflush4.1 文本文件FILE结构体4.2 二进制文件没有行概念4.3 文件定位linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文本文件但不能读写二进制文件。用fread和fwrite可以读写文本文件和二进制文件 5.多线程pthread_create()查看线程top -Hps -xH | grep5.1 子线程未执行join5.2 线程传参区分线程th15.3 两子线程数字相加分别加到自己线程变量中5.4 两个线程同时加到一个全局变量s中5000数字小不会影响全局变量S要加锁数字大出现race condition 5.5 假共享两线程分别加到自己result数组中0和1两个线程两个result数组一个数字累加 6.动静态库.a指定.soLD_6.1 静态库链接库的文件名是libpublic.a链接库名是public缺点使用的静态库发生更新改变程序必须重新编译6.2 动态库动态库发生改变程序不需要重新编译动态库升级方便6.3 libc标准gnu libcglibc实现6.4 编译时为什么要加上 –lm ?man expLink with -lm 1.编译预处理C源程序 - 编译预处理【#开头指令和特殊符号进行处理删除程序中注释和多余空白行】- 编译 条件编译最常用的两种格式#ifdef和#ifndef 。#undef 取消已定义的标识符 如下book145.c和_public.c都有 #include_public.h会重复包含。 在_public.c中如下这样写_public.h就不会被重复包含。
2.gdb调试多进/线程中无法用
root 用户yum -y install gdbgdb -v。
3.makefile文件make是一个解释makefile中指令的命令工具
vi gcc.sh 如下sh gcc.sh。gcc -o 目标 依赖1 依赖2。makefile命令能被执行条件有两个1.目标不存在2.依赖已更新。 如上若只需要编译book2单个文件改变不重复编译其他文件即增量编译。vi makefile$前一个tab键不能8个空格。make默认是make all如果将all这行book3删除则make不会编译book3可指定make book3book3相当于标签。-欧2是让编译效率最高一般正式发布用。gcc命令选项 -c编译不链接。
4.文件fprint/fgets/fwrite/freadftell/rewind/fseek/fflush
4.1 文本文件FILE结构体 vi /tmp/test1.txt可见有5行记录不管执行多少次都是5行记录因为文件打开方式是w每次打开文件时都会清空原文件中的记录。
int main() {int fd;char buffer[5] {0};ssize_t bytesRead;fd open(/home_a/abcd, O_RDONLY, 0444);bytesRead read(fd, buffer, 4);if (bytesRead -1) {printf(read error);return 1;}printf(Read %zd bytes: %s\n, bytesRead, buffer); //Read 4 bytes: 0xffreturn 0;
}4.2 二进制文件没有行概念 #include stdio.h
int main()
{char *filename Shanghai;FILE *fp fopen(filename, rb);if (fp NULL){printf(打开%s文件错误, filename);return -1;}int n;for (int i 0; i 10000; i){fread(n, sizeof(int), 1, fp);printf(%d\n , n);}fclose(fp);return 0;
}4.3 文件定位linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文本文件但不能读写二进制文件。用fread和fwrite可以读写文本文件和二进制文件
文件内部有一个位置指针用来指向当前读写的位置也就是读到第几个字节。在文件打开时如果打开模式是r和w位置指针指向文件的第一个字节。如果打开模式是a位置指针指向文件的尾部每当从文件里读n个字节或文件里写入n个字节后位置指针会后移n个字节。
文件位置指针与C中指针不是一回事位置指针仅仅是一个标志表示文件读写到的位置即读写到第几个字节不表示地址。文件每读写一次位置指针就会移动一次不需要你在程序中定义和赋值由系统自动设置。
#include stdio.h
int main(int argc, char **argv)
{FILE *fpfopen(/sys/bus/i2c/devices/20-0048/hwmon/hwmon1/in0_input,w);if(!fp){puts(fail);}fclose(fp);
}FILE *fptime;
fptimefopen(/tmp/time,w);
time_t time_log time(NULL);
struct tm* tm_log localtime(time_log);
fprintf(fptime, flag[%d] LINE[%d] %04d-%02d-%02d %02d:%02d:%02d\r\n,sensor_flag, __LINE__, tm_log-tm_year 1900, tm_log-tm_mon 1, tm_log-tm_mday, tm_log-tm_hour, tm_log-tm_min, tm_log-tm_sec);
fflush(fptime);
fclose(fptime);if(rc0)
{FILE *fpLedLogfopen(/tmp/error,a);fprintf(fpLedLog,error__%u__\r\n,__LINE__);fclose(fpLedLog);goto err;
}FILE *fpLedColorfopen(led_color,w);
fseek(fpLedColor,0,SEEK_SET);
fprintf(fpLedColor,%s,sensor_flag?LED_GREEN_CODE:LED_YELLOW_CODE);
fflush(fpLedColor);
fclose(fpLedColor);int main(int argc, char **argv)
{if(2 argc){FILE *fpLedCtrlfopen(/sys/bus/i2c/devices/0-000d/sys_led_ctrl,w);FILE *fpLedColorfopen(/sys/bus/i2c/devices/0-000d/sys_led_color,w);FILE *fpLedLogfopen(/var/log/sensorMon.log,w); fprintf(fpLedCtrl,0x1);fprintf(fpLedColor,%s,argv[1]);fprintf(fpLedLog,%s\r\n,argv[1]); fclose(fpLedCtrl);fclose(fpLedLog);fclose(fpLedColor);}
}int mysprintf(char *outBuffer, char *format, ...)
{va_list aptr;int ret;va_start(aptr, format);ret vsprintf(outBuffer, format, aptr);va_end(aptr);return(ret);
}if( realvalue 0 )
{CompareValueThreshold(realvalue,node[i]);strcat(node[i].path,node[i].node);if(0strcmp(P1V8_VDDO(SWITCH),node[i].name) || 0strcmp(P1V2(SWITCH),node[i].name))RecordEventLog(LOG_ERR,\n [%d] throw a %s\n,i,sta?SENSOR_ABNORMAL:SENSOR_NORMAL);
}FILE *frightfopen(/tmp/right,w);
for(i0;iarraysize;i)
{fprintf(fright,[%d] %s (%s)\r\n,i,node[i].path,node[i].desc);
}
fclose(fright);5.多线程pthread_create()查看线程top -Hps -xH | grep
5.1 子线程未执行join
如下线程thread和进程process区别process不能共享内存。 如下线程主函数void* 。pthread_create的第四个参数是myfunc的参数。
5.2 线程传参区分线程“th1” 5.3 两子线程数字相加分别加到自己线程变量中 如下解决上面代码重复太多问题将0-2500和2500-5000当参数传进来。
5.4 两个线程同时加到一个全局变量s中5000数字小不会影响 全局变量S要加锁数字大出现race condition 5.5 假共享两线程分别加到自己result数组中0和1两个线程两个result数组一个数字累加 如下定义s为局部变量 结构体取出result比上面要快。 time ./example6始终比example5快将50000000多加一个0快的更多。为什么 ? 因为假共享false sharing如下是一个框即单核cpu不会false sharing。 如下多核运算结果距离近example5里result变量在线程主函数外cpu线程计算要从RAM中拉取。example6里的s为局部变量放在两个线程主函数里即cpu缓存里做计算cpu两个核里两个缓存不会互相影响。所以example6不会falsing sharing速度快。 如下解决假共享cpu的cache短RAM里很长第一个线程结果保存在0位置第二个线程结果保存在100位置cache只更新自己长度的一小段如下4段空间换时间。
#if 0
int a200;
int b100;
pthread_mutex_t lock; //互斥锁的宏
void ThreadA(void)
{printf(线程A.....\n);pthread_mutex_lock(lock);a-50; //aa-50sleep(5);b50; //bb50printf(a:%d,b:%d\n,a,b);pthread_mutex_unlock(lock);
}
void ThreadB(void)
{printf(线程B.....\n);sleep(1);pthread_mutex_lock(lock);//加锁printf(%d\n,ab);pthread_mutex_unlock(lock);//解锁
}
int main(void)
{pthread_t tida,tidb;pthread_mutex_init(lock,NULL);//建立一个互斥锁pthread_create(tida,NULL,(void *)ThreadA,NULL); //创建一个线程1.句柄2.线程属性3.线程函数4.函数的参数pthread_create(tidb,NULL,(void *)ThreadB,NULL);pthread_join(tida,NULL);//等待一个线程结束pthread_join(tidb,NULL);pthread_mutex_destroy(lock);return 1;
}
// -server:~/bak$ gcc test.c -lpthread
// -server:~/bak$ ./a.out
// 线程A.....
// 线程B.....
// a:150,b:150
// 300
#endif6.动静态库.a指定.soLD_
公用函数库的public.cpp是源代码对任何人可见实际开发出于保密并不希望提供公用函数库源代码。C/C提供了一个保证代码安全性方法public.cpp编译成库(静态库与动态库)。
// public.h
#ifndef PUBLIC_H
#define PUBLIC_H 1
#include stdio.h
void func(); // 自定义函数的声明
#endif// public.cpp
#include public.h
void func() // 自定义函数的实现
{printf(我心匪石不可转也。我心匪席不可卷也。威仪棣棣不可选也。\n);
}// book265.cpp
#include public.h // 把public.h头文件包含进来
int main()
{func();
}g -o book265 book265.cpp public.cpp
./book265
我心匪石不可转也。我心匪席不可卷也。威仪棣棣不可选也。6.1 静态库链接库的文件名是libpublic.a链接库名是public缺点使用的静态库发生更新改变程序必须重新编译
gcc -c -o libpublic.a public.cpp使用静态库的方法一直接把调用者源代码和静态库文件名一起编译
g -o book265 book265.cpp libpublic.a使用静态库的方法二用L参数指定静态库文件的目录-l参数指定静态库名如果要指定多个静态库文件的目录用法是“-L/目录1 -L目录2 -L目录3”如果要指定多个静态库用法是“-l库名1 -l库名2 -l库名3”。
g -o book265 book265.cpp -L/home/w/demo -lpublic./book265
我心匪石不可转也。我心匪席不可卷也。威仪棣棣不可选也。6.2 动态库动态库发生改变程序不需要重新编译动态库升级方便
g -fPIC -shared -o libpublic.so public.cpp使用动态库的方法与使用静态库的方法相同。如果在动态库文件和静态库文件同时存在优先使用动态库编译
g -o book265 book265.cpp -L/home/w/demo -lpublic执行程序./book265时出现以下提示/book265: error while loading shared libraries: libpublic.so: cannot open shared object file: No such file or directory因为采用了动态链接库的可执行程序在运行时需要指定动态库文件的目录Linux系统中采用LD_LIBRARY_PATH环境变量指定动态库文件的目录。采用以下命令设置LD_LIBRARY_PATH环境变量。
export LD_LIBRARY_PATH/home/w/demo:.如果要指定多个动态库文件的目录用法是“export LD_LIBRARY_PATH目录1:目录2:目录3:.”目录之间用半角的冒号分隔最后的圆点指当前目录。接下来修改动态库中func函数的代码
// printf(我心匪石不可转也。我心匪席不可卷也。威仪棣棣不可选也。\n);
printf(生活美好如鲜花不懂享受是傻瓜\n);如下重新编译动态库无需重新编译book265直接执行程序。
g -fPIC -shared -o libpublic.so public.cpp./book265
生活美好如鲜花不懂享受是傻瓜6.3 libc标准gnu libcglibc实现
编译【预处理语法检查编译.c-.s汇编文件汇编.s-.o二进制文件链接多个.o合并成1个执行文件】的最后阶段将依赖引入过程叫链接so文件通过mmap加载进内存动态链接的a.out文件小且内存占用小此外动态链接在so库更新后不需重新编译一般首选。很多进程用到C语言libc.so里stdio.h里打印函数如果通过静态链接这样占用的内存多。 static指定静态链接。gcc是gnu的编译工具集合gcc不光编译c语言且支持很多平台 如下系统没有glibc库。
6.4 编译时为什么要加上 –lm ?man expLink with -lm
// 代码一
#include stdio.h
#include math.h //exp
int main(int argc, char const *argv[]){printf(The exponential value of %lf is %lf\n, 0, exp(0));printf(The exponential value of %lf is %lf\n, 01, exp(01)); //e的1次幂printf(The exponential value of %lf is %lf\n, 02, exp(02));return(0);
}// 代码二
#include stdio.h
#include math.h
int main(int argc, char const *argv[]){double x 0;printf(The exponential value of %lf is %lf\n, x, exp(x));printf(The exponential value of %lf is %lf\n, x1, exp(x1));printf(The exponential value of %lf is %lf\n, x2, exp(x2));return(0);
}代码一调用exp传入的参数是常量为0 。代码二调用exp传入的参数是变量 x代码一会不会在运行之前就计算好了呢如下代码一没有看到调用exp的身影当传入参数为常量时就已计算好了值最后不需调用exp函数。代码二通过如下main.s汇编代码可见多次调用call函数。 math.h中声明的库函数还有一点特殊之处gcc命令行必须加-lm选项因为数学函数位于libm.so库文件中这些库文件通常位于/lib目录下-lm选项告诉编译器程序中用到的数学函数要到这个库文件里找。
gcc a.c -o a.outarm-linux-gcc a.c -o b.out如果执行out文件出现No such file or directory则将如下两个so文件互相ln -s建软链接。