文章目录

  • 1.编译预处理:C源程序 - 编译预处理【#开头指令和特殊符号进行处理,删除程序中注释和多余空白行】- 编译
  • 2.gdb调试:多进/线程中无法用
  • 3.makefile文件:make是一个解释makefile中指令的命令工具
  • 4.文件:fprint/fgets/fwrite/fread,ftell/rewind/fseek/fflush
    • 4.1 文本文件:FILE结构体
    • 4.2 二进制文件:没有行概念
    • 4.3 文件定位:linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文本文件,但不能读写二进制文件。用fread和fwrite可以读写文本文件和二进制文件
  • 5.多线程:pthread_create(),查看线程top -H,ps -xH | grep
    • 5.1 子线程未执行:join
    • 5.2 线程传参区分线程:"th1"
    • 5.3 两子线程数字相加:分别加到自己线程变量中
    • 5.4 两个线程同时加到一个全局变量s中:5000数字小不会影响
      • 全局变量S++要加锁:数字大出现race condition
    • 5.5 假共享:两线程分别加到自己result数组中,0和1两个线程,两个result数组(一个数字累加)
  • 6.动静态库:.a,指定.so,LD_
    • 6.1 静态库:链接库的文件名是libpublic.a,链接库名是public,缺点使用的静态库发生更新改变,程序必须重新编译
    • 6.2 动态库:动态库发生改变,程序不需要重新编译,动态库升级方便
    • 6.3 libc(标准):gnu libc(glibc)(实现)
    • 6.4 编译时为什么要加上 –lm ?:man exp:Link with -lm

1.编译预处理:C源程序 - 编译预处理【#开头指令和特殊符号进行处理,删除程序中注释和多余空白行】- 编译


条件编译:最常用的两种格式#ifdef和#ifndef 。#undef :取消已定义的标识符


如下book145.c和_public.c都有 #include"_public.h",会重复包含。

在_public.c中如下这样写,_public.h就不会被重复包含。

2.gdb调试:多进/线程中无法用

root 用户:yum -y install gdb,gdb -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 book3,book3相当于标签。-欧2是让编译效率最高,一般正式发布用。gcc命令选项 :-c编译不链接。

4.文件:fprint/fgets/fwrite/fread,ftell/rewind/fseek/fflush

4.1 文本文件:FILE结构体



vi /tmp/test1.txt,可见有5行记录,不管执行多少次都是5行记录,因为文件打开方式是w,每次打开文件时都会清空原文件中的记录。

int main(int argc, char ** argv)
{if (-1){printf("111\n");}  // 非0打印else{printf("222\n");}
}int main() {int fd;char buffer[5] = {0};ssize_t bytesRead;fd = open("/home_a/yutao/abak/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;
}// #define BIT(n) (1 << (n))
int main(void)
{int ret = chmod("/abak/a.c",S_IRUSR);if (ret == 0) {printf("111\n");}else {printf("222\n");}  ///if ((0)){printf("444\n");}else printf("555\n"); ///if (!(0)){printf("666\n");} ///else printf("777\n");if (!(1 & 1)){printf("888\n");}else printf("999\n"); ///
}

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 *fp=fopen("/sys/bus/i2c/devices/20-0048/hwmon/hwmon1/in0_input","w");if(!fp){puts("fail");}fclose(fp);
}FILE *fptime;
fptime=fopen("/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(rc<0)
{FILE *fpLedLog=fopen("/tmp/error","a");fprintf(fpLedLog,"error__%u__\r\n",__LINE__);fclose(fpLedLog);goto err;
}FILE *fpLedColor=fopen(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 *fpLedCtrl=fopen("/sys/bus/i2c/devices/0-000d/sys_led_ctrl","w");FILE *fpLedColor=fopen("/sys/bus/i2c/devices/0-000d/sys_led_color","w");FILE *fpLedLog=fopen("/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(0==strcmp("P1V8_VDDO(SWITCH)",node[i].name) || 0==strcmp("P1V2(SWITCH)",node[i].name))RecordEventLog(LOG_ERR,"\n [%d] throw a %s\n",i,sta?"SENSOR_ABNORMAL":"SENSOR_NORMAL");
}FILE *fright=fopen("/tmp/right","w");
for(i=0;i<arraysize;i++)
{fprintf(fright,"[%d] %s (%s)\r\n",i,node[i].path,node[i].desc);
}
fclose(fright);

5.多线程:pthread_create(),查看线程top -H,ps -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 a=200;
int b=100;
pthread_mutex_t lock; //互斥锁的宏
void ThreadA(void)
{printf("线程A.....\n");pthread_mutex_lock(&lock);a-=50; //a=a-50sleep(5);b+=50; //b=b+50printf("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",a+b);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
#endif

6.动静态库:.a,指定.so,LD_

公用函数库的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 libc(glibc)(实现)

编译【预处理(语法检查),编译(.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 exp:Link 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", 0+1, exp(0+1)); //e的1次幂printf("The exponential value of %lf is %lf\n", 0+2, exp(0+2));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", x+1, exp(x+1));printf("The exponential value of %lf is %lf\n", x+2, exp(x+2));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建软链接。

【c2】编译预处理,gdb,makefile,文件,多线程,动静态库相关推荐

  1. 头文件和库文件区别,动态库和静态库的区别,动静态库的生成

    文章目录 一.什么是头文件?什么是库文件?有什么区别? 先说总结 目标文件 二.什么是静态库?什么是动态库?有什么区别? 三.为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明 ...

  2. 【Linux篇】第十一篇——动静态库(动静态库的介绍+动静态库的打包与使用)

    动静态库的基本原理 认识动静态库 动静态库的概念 静态库的打包与使用 静态库的打包 静态库的使用 动态库的打包与使用 动态库的打包 动态库的使用 动静态库的基本原理 动静态库的本质就是可执行程序的&q ...

  3. adb: createprocessw failed: 系统找不到指定的路径_gcc编译过程、gcc命令参数、静态库和动态库搜索路径...

    一.gcc编译过程 gcc -E hello.c -o hello.s //预处理 gcc -S hello.s -o hello.i //编译 gcc -c hello.i -o hello.o / ...

  4. 【Linux】磁盘结构/文件系统/软硬链接/动静态库

    文章目录 前言 一.磁盘结构 1.磁盘的物理结构 2.磁盘的存储结构 3.磁盘的逻辑结构 二.文件系统 1.对 IO 单位的优化 2.磁盘分区与分组 3.对分组的具体管理方法 4.文件操作 三.软硬链 ...

  5. Linux下动静态库的打包与使用C C++

    目录 前言 为什么用动静态库 动态链接与静态链接 底层优缺点 Linux下的动静态库 动静态库的对比 打包静态库 使用静态库 打包动态库 使用动态库 小结 win下打包动静态库 前言 为什么用动静态库 ...

  6. 【C/C++10】天气APP:MySQL/PostgreSQL,环境变量/动静态库,Linux/Oracle字符集

    文章目录 1.MySQL:decimal,find . .-print 2.PostgreSQL:$ 3.环境变量:tnsnames.ora,curl 3.1 对单一用户生效: .bash_profi ...

  7. 编译-POCO C++支持iOS平台的静态库

    一.POCO C++ library简介 POCO C++ library是一个C++编写的跨平台库,主要实现网络连接.数据库管理以及服务器,适用于跨平台.嵌入式. 二.为Xcode编译POCO C+ ...

  8. [OS-Linux]详解Linux的文件系统、inode和动静态库

    本文详解了Linux中的文件系统,包括inode.软连接,硬链接.动静态库. 目录 一.理解文件系统 二.inode 三.硬链接和软连接 1.硬链接 2.软连接 四.动态库和静态库 1. 静态库与动态 ...

  9. Linux | 编译器gcc/g++的使用【动静态库的认识】

    文章目录 一.对程序的认知 && 初识gcc 1.程序是如何诞生的? 2.gcc的初步认识 3.如何使用gcc 二.gcc逐步分析程序的翻译环境 1.预编译[进行宏替换] 2.编译[C ...

  10. 学习系统编程No.15【深入动静态库】

    引言: 北京时间:2023/4/5/11:04,天空阴沉,非常符合今天清明节的身份,不知道是大部分学校都放假一天,还是就我们学校,反正清明节回不了家,昨天上了一个中国优秀传统文化的课,老师给我们讲了李 ...

最新文章

  1. 【实用主义】如何用nodejs自动定时发送邮件提醒?
  2. 我为什么强烈反对程序员加班?
  3. Class.getResource()、ClassLoader.getResource()和this.class.getClassLoader()解析
  4. c语言指针++_C ++此指针| 查找输出程序| 套装3
  5. 企业微信_新建自建H5小程序应用及主页与菜单设置
  6. docker 随笔记录
  7. shell编程入门步步高(七、流程控制)
  8. java 蓝桥杯训练 数的统计
  9. 【Elasticsearch】es 使用Rollup在Elasticsearch 6.3中合并旧日志 上卷 Rollup
  10. spark学习-57-Spark下Scala版HBase下的根据权重获取最真实数据
  11. c++指针各种用法小结
  12. 演说之禅:演说中的图效优势
  13. Mysql 存储过程、存储函数 与 递归查询
  14. 【边喝caffee边Caffe 】(一)Caffe的安装
  15. 2022新版千月影视双端APP带H5功能开源程序支持当面付和易支付
  16. qq显示下线通知什么意思_qq最近登录设备显示其他设备,但我手机没有下线通知,怎么回事...
  17. 简单介绍红白机的发声系统以及其它音源 MMC
  18. 支持tcam的服务器,使用tcam实现数据流的选择性路由
  19. 如何网页中嵌入谷歌地图
  20. 【Docker】docker安装elasticsearch集群,Kibana安装以及开启认证

热门文章

  1. VTK及计算机图形学培训资料
  2. Tracy JS 小笔记 - 数据类型, typeof,类型转换
  3. 300+篇运维、数据库等实战资料免费下载(文章+PDF+视频,持续更新)
  4. Qt Creator - UI Designer可视化设计窗体
  5. Unity AR 两指手势实现物体放大缩小功能
  6. [转贴]一封电脑程序员的发烧情书 V1.0
  7. 读书笔记-现代操作系统-6死锁-6.3鸵鸟算法6.4死锁检测和死锁恢复
  8. 教程 - 深度探讨在 Vue3 中引入 CesiumJS 的最佳方式 _
  9. STM32物联网项目——WIFI模块联网
  10. java dox4j实现word转pdf