【C1】数据类型,常量变量,输入输出,运算符,if/switch/循环,/数组,指针,/结构体,文件操作,/编译预处理,gdb,makefile,线程
文章目录
- 1.数据类型:单双引号,char(1B),int/float(32位系统,大小一样4B,但存储方式不同),double(8B),long double(12B)
- 2.常量和变量:memset,const
- 3.输出和输入:gets获取一行数据,并作为字符串处理
- 4.运算符:前先加1,sizeof
- 5.if/switch/循环:上下,else if
- 6.数组:存数据类型相同的数据,数组下标越界导致core dump段错误
- 7.指针:指针数组:这个数组的所有元素都是指针类型。数组指针:这个指针存放着一个数组的首地址
- 7.1 p是地址,*p是指向的内容:01指0x01。&a:拿a的地址赋给。地址(p),值(*p),变量名
- 7.2 函数调用:复制a值,指向a
- 7.3 函数返回:复制指针
- 7.4 数组和指针转换:指针转不了数组,数组可转为指针
- 7.5 const型指针:不可修改
- 8.main函数的参数:main函数的参数是从命令提示符下执行程序时传入
- 9.static/extern/堆内存:realloc扩建
- 10.动静态库:.a,指定.so,LD_
- 10.1 静态库:链接库的文件名是libpublic.a,链接库名是public,缺点使用的静态库发生更新改变,程序必须重新编译
- 10.2 动态库:动态库发生改变,程序不需要重新编译,动态库升级比较方便
- 10.3 libc:gnu libc(glibc),musl libc(alpine)
- 11.结构体:struct,memcpy,memset
- 12.文件操作:FILE结构体,fprint/fgets,fwrite/fread,ftell/rewind/fseek,fflush
- 12.1 二进制文件的读写:没有行概念
- 12.2 文件定位:linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文本文件,但不能读写二进制文件。用fread和fwrite可以读写文本文件和二进制文件
- 13.编译预处理:C源程序 - 编译预处理【对预处理指令即以#开头指令和特殊符号进行处理,删除程序中注释和多余空白行】- 编译
- 14.gdb调试:set args,b/r,n/s
- 15.makefile文件:依赖文件功能
- 16.多线程:pthread_create(),查看线程top -H,ps -xH | grep
- 16.1 子线程未执行:join
- 16.2 线程传参区分线程:"th1"
- 16.3 两子线程数字相加:分别加到自己线程变量中
- 16.4 两个线程同时加到一个全局变量s中:5000数字小不会影响
- 16.5 全局变量S++要加锁:数字大出现race condition
- 16.6 假共享:两线程分别加到自己result数组中
1.数据类型:单双引号,char(1B),int/float(32位系统,大小一样4B,但存储方式不同),double(8B),long double(12B)
编译器(compiler)与解释器(interpreter)
:编译型语言
像C/C++/golang/rust等都会用到编译器,并且都是AOT(ahead of time)预先编译,编译将源码编译成机器码生成二进制文件,可直接运行该文件,因为是机器码,所以运行效率很高,缺点是不够灵活,改代码的话要重新编译,此外平台依赖严重,linux平台编译出来的二进制文件无法在windows运行,跨平台还需借助交叉编译。
解释型语言
像python/js/php等使用解释器逐行解释,不需要生成二进制文件,灵活如线上php系统,改了代码功能直接生效,但解释型语言运行效率低。还有一些语言本身是用解释器在运行,但在运行时使用了编译器进行JIT(just in time)实时编译如java,是半解释半编译型语言,JIT将运行到的代码块在运行时编译成机器码,既可保证跨平台性,又能使热代码高效运行。
app可直接调os接口,也可以调c库,c库再去调os接口。一个程序只有一个main函数。#include
:包含其他文件预处理指令。main(){}
:这个是最简单的C程序。<stdio.h>头文件包含printf。yum -y install gcc,yum install gcc-c++。
gcc main.c int_sum.c float_sum.c
-o(output) main -Wall
(显示所有警告) -I../include
(-I后面没空格,不加-I就在main.c中指定头文件的相对路径)。gcc main.c -o main -Wall
-I../include
-L../lib
-lsum
(有库文件/lib/ibsum.so就只要main.c就行)。
1.基本类型
:字符型(char)
:描述单个字符,用单引号包含起来,如’a’,‘A’,‘1’,'$'等,键盘能输入的英文和半角符号
都是字符。关键字char是character(字符)的简写。中文里的汉字和标点符号是两个字节,不能算一个字符
,'¥','好','。'
这些都是非法的。
整型(int)
:整数在计算机上是准确表示的,如123,500,0,-10等。关键字int是integer(整数)的简写。
浮点型(double)
:描述实数有小数位,如10.0,123.55,3459.98,-50.3,实数在计算机上一般是近似表示的。只有三种:float,double,long double。
2.字符串
:描述多个字符,用双引号
包含起来,可以是英文,数字,中文,标点符号,半角全角,空字符串都可以。
3.构造类型
:由已知的基本类型通过一定的构造方法构造出来的类型,包括数组和结构体。
4.指针类型
:指针可以指向内存地址,主要用于函数的参数传递。
浮点数不是2的0次方+2的1次方…,用下面公式。
不用管如上公式,记住:浮点数最小可识别精度和浮点数即0.1本身大小相关,而不是和float相关。
1.获取字符串的长度(strlen)
5.字符串拼接(strncat)
6.字符串比较(strcmp,strncmp)
#include <stdio.h>
#include <string.h>
int main()
{char *names = "PSU";if(strcmp(names,"PSU")==0){puts("aaaa");}
}int main() { // error: expected ‘)’ before string constant 少了int main()char name_str[30];char name_str1[30];strcpy(name_str,"/sys/bus/i2c/devices/");strcpy(name_str1,"17-0064");strcat(name_str,name_str1);printf("is : %s\n", name_str); // /sys/bus/i2c/devices/17-0064
}putchar('w');putchar('w');
printf("[%s]__%4d__[%s] %s \n", __FILE__, __LINE__, __FUNCTION__, n->name);
8.字符串查找(strstr)
#include <stdio.h>
#include <string.h>
int main ()
{char str1[15];char str2[15];int ret;strcpy(str1, "abcdef");strcpy(str2, "ABCDEF");ret = strcmp(str1, str2);if(ret < 0){printf("str1 小于 str2");}else if(ret > 0) {printf("str1 大于 str2");}else {printf("str1 等于 str2");}return(0); //str1 大于 str2
}
#include<stdio.h>
#include<string.h>
#include <pthread.h>
#include <unistd.h>#if 0
int main() { // int a;// char pNum[]="0x7f";// a=strtoul(pNum,0,16);// printf("%d\n",a); //127// return 0;char str[30] = "2030300 This is test";char *ptr;long ret;ret = strtoul(str, &ptr, 10);printf("数字(无符号长整数)是 %lu\n", ret); // 2030300printf("字符串部分是 |%s|\n", ptr); // This is testreturn 0;
}
#endif#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);pthread_create(&tidb,NULL,(void *)ThreadB,NULL);//创建一个线程,1.句柄,2.线程属性,3.线程函数,4.函数的参数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
2.常量和变量:memset,const
1.静态数据:
永久性数据,一般存储在硬盘中,只要硬盘没坏数据都是存在的,电脑关机重启后依然存在。写程序目的就是告诉计算机如何输入,处理,传输,存储和展示数据。
2.动态数据(临时数据):
程序运行过程中,动态产生的临时数据,一般存储在内存中,软件或者电脑关闭则这些临时数据会被清除。为什么不把动态数据存放到硬盘呢?因为访问内存的速度比访问硬盘快很多倍。
3.数据大小
:(1)数据都是由二进制的0和1组成。
(2)数据都会占用空间,静态数据占硬盘空间,动态数据占内存空间。
(3)数据占用空间的最小单位是比特(bit)。一个1或者0就是一个比特,即1bit。
(4)计算机中,以字节为单位存储数据。1字节=8比特(1Byte=8bit)。
(5)1B=8bit,1KB=1024B,1MB=1024KB,1GB=1024MB…
常量:
即常数,表示固定的数据:(1)字符常量 如’6’,‘a’,‘F’(不能是中文,例如:‘男’)
(2)整数常量 如6,27,-299
(3)浮点数常量 如5.43,-2.3,5.67,6.0
(4)字符串常量 如’‘625’‘,’‘女’‘,’‘nanbc’‘,’‘西施’’
变量:
如果数据的值不确定的,或者经常需要改变,或者临时取值的,则用变量取值。常量指具体数据,变量指存数据的容器,水与水桶一样。变量使用前必须先进行声明(或定义),在内存中分配一块存储空间给变量,用于存放数据。
1.整数型,字符型,浮点型变量的定义
int ii;
//定义整数型变量,用于存放整数,关键字int,是单词integer(整数)的缩写。
char cc;
//定义字符串变量用关键字char,是单词charcter(字符)的缩写,存放字符。
double money;
//定义浮点型变量,用于存放浮点数,关键字double。
2.字符串变量的定义
C语言中没有字符串这个数据类型,而是用字符数组来表达字符串。char name[21];定义一个可以存放20字符的字符串即20个英文或10个中文。字符串不是C语言的基本数据类型
,不能用=赋值,不能用><比较大小,不能用+拼接,不能用==和!=判断两个字符串是否相等,要用函数。
3.变量的命名
变量名属于标识符,需要符合标识符的命名规范,如下:
1)变量名的第一个字符必须是字母或下划线,不能是数字和其它字符。
2)变量名中的字母是区分大小写的。比如 a 和 A 是不同的变量名,num 和 Num 也是不同的变量名。
3)变量名绝对不可以是C语言关键字。
关键字
也称为保留字,共32个,也就是说这些单词在C语言中有特别的含义,程序员不能把它用于变量或函数的命名。auto
:声明自动变量。break
:跳出当前循环。case
:开关语句分支。char
:声明字符型变量或函数返回值类型。const
:声明只读变量。continue
:结束当前循环,开始下一轮循环。default
:开关语句中的“默认”分支。do
:循环语句的循环体。double
:声明双精度浮点型变量或函数返回值类型。else
:条件语句否定分支(与 if 连用)。enum
:声明枚举类型。extern
:声明变量或函数是在其它文件或本文件的其他位置定义。float
:声明浮点型变量或函数返回值类型。for
:一种循环语句。goto
:无条件跳转语句。if
:条件语句。int
: 声明整型变量或函数。long
:声明长整型变量或函数返回值类型。register
:声明寄存器变量。return
:子程序返回语句(可以带参数,也可不带参数)。short
:声明短整型变量或函数。signed
:声明有符号类型变量或函数。sizeof
:计算数据类型或变量长度(即所占字节数)。static
:声明静态变量。struct
:声明结构体类型。switch
:用于开关语句。typedef
:用以给数据类型取别名。unsigned
:声明无符号类型变量或函数。union
:声明共用体类型。void
:声明函数无返回值或无参数,声明无类型指针。volatile
:说明变量在程序执行中可被隐含地改变。while
:循环语句的循环条件。
变量的初始化
:在main函数内部定义的变量称为局部变量,局部变量被定义后,系统不会对其初始化,必须自己写程序初始化。
多变量定义
:int ii,jj;,const是constant缩写,意思是“恒定不变的”!它是定义只读变量的关键字,或者说 const 是定义常变量的关键字。用 const定义常变量
方法很简单,就在通常定义变量时前面加 const 即可,如:const double pi = 3.1415926;
用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使赋相同的值
也不可以。所以说它定义的是只读变量。这也就意味着必须在定义的时候就给它赋初值,如果程序中试图改变它的值,编译的时候就会报错。
1.整数型,字符型,浮点型变量初始化
:就是赋0值,也可在定义时初始化。
int ii=0; // 定义整数型变量并初始化
char cc=0; // 定义字符型变量并初始化
double money=0; // 定义浮点型变量并初始化
也可以先定义,然后再初始化
int ii; // 定义整数型变量
char cc; // 定义字符型变量
double money; // 定义浮点型变量
ii=0; // 初始化ii为0
cc=0; // 初始化cc为0
money=0; // 初始化money为0
2.字符串变量的初始化
:对字符串变量来说,初始化就是把内容清空。
char name[21]; // 定义一个可以存放20字符的字符串
memset(name,0,sizeof(name)); // 清空字符串name中的内容
3.未初始化的变量示例
:未初始化的变量会导致在内存中可能有垃圾值。
3.输出和输入:gets获取一行数据,并作为字符串处理
数据输出:
在C语言中,有三个函数可以把数据输出到屏幕。
putchar 用于输出单个字符。
puts 输出字符串。
printf函数是格式化输出函数, 用于向屏幕输出数据,printf函数的调用方法是: printf(格式化字符串,参数列表);
1.输出描述性的文字
输出的文字用双引号包含起来,在文字最后加上\n表示换一行,多个\n可以换多行。
printf(“我心非席,不可卷也,我心非石,不可转也。\n”);
以上代码将在屏幕上输出文字:我心非席,不可卷也,我心非石,不可转也。
输出文字之后,再输出一个换行。
2.输出整数
输出的整数常量或整数变量用%d表示,在参数中列出待输出的整数常量或整数变量。
printf(“我年龄是%d岁。\n”,18);
int age=18;
printf(“我年龄是%d岁。\n”,age);
3.输出字符
输出的字符常量或字符变量用%c表示,在参数中列出待输出的字符常量或字符变量。
printf(“我姓别是:%c。\n”,‘x’); // 姓别:x-男;y-女
char xb=‘x’;
printf(“我姓别是:%c。\n”,xb);
4.输出浮点数
输出的浮点型常量或浮点型变量用%lf表示,在参数中列出待输出的浮点型常量或浮点型变量。
printf(“我体重是%lf公斤。\n”,62.5);
double weight=62.5;
printf(“我体重是%lf公斤。\n”, weight);
5.输出字符串
输出的字符串常量或字符串型变量用%s表示,在参数中列出待输出的字符串常量或字符串变量。
printf(“我的姓名是%s。\n”,“豫让”);
char name[21];
memset(name,0,sizeof(name));
strcpy(name, “豫让”);
printf(“我的姓名是%s。\n”,name);
如下short是普通int的一半,d是十进制。
如下32指32字节。
scanf输入
:scanf函数是格式化输入函数, 用于向接受键盘输入的数据,用户输入数据完成后,需按回车键(Enter)结束输入。scanf函数的调用方法是: scanf(格式化字符串,参数列表)。注意,不要在scanf的格式化字符串的最后加\n。
1.输入整数
输入整数的格式用%d表示,在参数中列出整数型变量名,用于保存输入的数据。
在输入数据之前,一般要先输出一句话提示用户。下同。
int age=0;
printf(“请输入你的年龄:”); // 提示文字不要换行,让用户在后面输入,下同。
scanf("%d",&age); // 在变量名前要加符号&,键盘输入值放入age变量中去。
2.输入字符
输入字符的格式用%c表示,在参数中列出字符型变量名,用于保存输入的数据。
char xb=0;
printf(“请输入你姓别:”);
scanf(“%c”,&xb); // 在变量名前要加符号&
3.输入浮点数
输入浮点数的格式用%lf表示,在参数中列出浮点型变量名,用于保存输入的数据。
double weight=62.5;
printf(“请输入你体重:”);
scanf(“%lf”,&weight); // 在变量名前要加符号&。
4.输入字符串
输入字符串的格式用%s表示,在参数中列出字符串变量名,用于保存输入的数据。
char name[21];
memset(name,0,sizeof(name));
printf(“请输入你姓名:”);
scanf(“%s”,name); // 注意了,变量名前不加符号&,也不要问原因,以后再介绍。
5.输入多个内容
调用一次scanf函数可以输入多个数据,注意了,与单个数据的输入不同,多个数据的输入要等全部的数据输入完成后才按回车键。
int age=0;
char xb=0;
double weight=0;
char name[21];
memset(name,0,sizeof(name));
printf("请输入你的姓名、姓别(x-男;y-女),年龄和体重,中间用空格分隔:");
scanf("%s %c %d %lf",name,&xb,&age,&weight);
// 只有name变量前没加&,其它的都加了。因为name数组名就是首地址名。
scanf函数第一个参数(格式化字符串)的格式与后面的参数列表(变量的列表)要一一对应,不能多,不能少,顺序也不能错,否则会产生意外的结果。查找头文件:man memset显示如下。man 3 printf。1,2,3去试。
4.运算符:前先加1,sizeof
||
左边的命令返回假(命令返回值 $? == 1),||
右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作: 只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 语言内置了丰富的运算符,并提供了以下类型的运算符:1)算术运算符 2)赋值运算符 3)关系运算符 4)逻辑运算符 5)位运算符。如下浮点数没有取余数的说法。
如下ii++,就是ii=ii+1。
=是赋值,==才是判断两个数是否相等,C语言没有(之间,中间,之内或在某范围内)的关系运算符,例如年龄在25-30岁之间,只能表达为:年龄大于等于25岁并且年龄小于等于30岁。括号中表达式会优先执行
,sizeof(指针)大小永远是8字节,如下是sizeof运算符,sizeof是C语言的关键字,发挥着运算符的作用。
它主要用来计算某一个变量在当前系统的内存中所需占用的字节数。变量的类型包括char、int、double、数组、结构体和其它自定义的数据类型。sizeof不是函数。
产生这样的疑问主要是因为sizeof的书写确实有点像函数,比如:i = sizeof(int);这样的写法,就很容易让人误以为sizeof是一个函数。sizeof有两种写法:
1.用于数据类型
sizeof使用形式:sizeof(type)
数据类型必须用括号括住。如sizeof(int)。
printf(“sizeof(int)=%d\n”,sizeof(int)); // 输出结果:sizeof(int)=4
2.用于变量
sizeof使用形式:sizeof(var_name)或sizeof var_name
变量名可以不用括号括住。如sizeof(var_name),sizeof var_name等都是正确形式。
printf(“sizeof dd =%d\n”,sizeof dd); // 输出结果:sizeof dd =8
printf(“sizeof(dd)=%d\n”,sizeof(dd)); // 输出结果:sizeof(dd)=8
5.if/switch/循环:上下,else if
不要在if(判断条件)后面加分号。有;号就为空语句,下面都执行。c=(a>b)?a:b等同于两行:if(a>b) c=a;else c=b; if(0)
即0假。if(a=b)是赋值,不是判断。
当没有default时,如果所有case都匹配失败,那么就什么都不执行。char day=0,scanf(‘%c’',&day),case ‘0’。
case后面必须是一个整数
,或者是结果为整数的表达式
,但不能包含任何变量。
#include<stdio.h>
int main()
{int a=1, b=2, re;char c;scanf("%c", &c);switch(c){case '+':re = a + b;break;case '$':re = a - b;re++;break;case '#':{int other = 3; // switch语句里定义了新的变量 ,加{}re = a + b + other;break;}default:printf("Illegal input!\n");break;}printf("%d\n", re);
}$gcc -o main *.c -lm
$main
Illegal input!
0
如下do-while先执行一次循环。
continue跳到循环首部,break跳出循环。
6.数组:存数据类型相同的数据,数组下标越界导致core dump段错误
定义数组时,数组的长度必须是整数
(可以是常量,也可以是变量)。
内存是线性的,b里放了2个a。
如下如果用msg[1],虽然越界了,但是系统给结构体分配很多字节,所以不报错。可用msg[0]到msg[n-1]。
函数声明和函数定义是两个概念,但变量声明和变量定义是一个概念。
7.指针:指针数组:这个数组的所有元素都是指针类型。数组指针:这个指针存放着一个数组的首地址
7.1 p是地址,*p是指向的内容:01指0x01。&a:拿a的地址赋给。地址(p),值(*p),变量名
char str[10];
char strbuf[10];char *a(void)
{FILE *fp=0;if ((fp=fopen("ab","rt")) ==0){printf("1111111");}if (fgets(strbuf, 10, fp) == NULL) {printf("2222222");fclose(fp);}strcpy(str,"B");strcat(str,strbuf);fclose(fp);return str;
}int main()
{char *b=a();printf("%s\n", b);
}
如下fclose要早于printf。
int *p 未赋值的指针称为野指针,危险的,a=100,p=&a指向合法区域。或如下空指针的两种写法也可防止野指针。
7.2 函数调用:复制a值,指向a
1.
如下main中走到increament跳到这函数中,拷贝一份给increament中的a。main中的a和increament中的a各自独立一块内存,只是名字一样。
2.
一定要通过increasement函数对a有修改怎么办?如下必须用到指针,increament运行结束后指针销毁。
7.3 函数返回:复制指针
如下当调用move_p时,p要往右移一位。move_p参数定义虽是指针,但调用时传入也是指针,复制一份。
7.4 数组和指针转换:指针转不了数组,数组可转为指针
7.5 const型指针:不可修改
8.main函数的参数:main函数的参数是从命令提示符下执行程序时传入
envp参数存放了当前程序运行环境的参数(env命令)。
9.static/extern/堆内存:realloc扩建
10.动静态库:.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
我心匪石,不可转也。我心匪席,不可卷也。威仪棣棣,不可选也。
10.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
我心匪石,不可转也。我心匪席,不可卷也。威仪棣棣,不可选也。
10.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");
printf("傻呀傻呀傻呀傻,比不上小鸟和乌鸦。\n");
如下重新编译动态库,无需重新编译book265,直接执行程序。
g++ -fPIC -shared -o libpublic.so public.cpp
./book265
生活美好如鲜花,不懂享受是傻瓜;
傻呀傻呀傻呀傻,比不上小鸟和乌鸦。
10.3 libc:gnu libc(glibc),musl libc(alpine)
gcc是gnu的编译工具集合,gcc不光编译c语言且支持很多平台。llvm提出中间文件格式IR,所有语言处理成IR格式文件(像java中class文件一样),将IR格式文件处理成可执行的二进制文件。
11.结构体:struct,memcpy,memset
C语言用结构体(struct)数据类型
存放一组不同数据类型
的数据。
结构体复制:基本类型用=,字符串用strcpy,结构体memcpy。
结构体作为函数的参数:结构体成员较多,函数参数的初始化和赋值的开销很大,最好的办法就是传递结构体变量的地址。
12.文件操作:FILE结构体,fprint/fgets,fwrite/fread,ftell/rewind/fseek,fflush
参数mode也是字符串,表示打开文件的模式,打开模式可以是下列值中一个。
vi /tmp/test1.txt,可见有5行记录,不管执行多少次都是5行记录,因为文件打开方式是w,每次打开文件时都会清空原文件中的记录。
12.1 二进制文件的读写:没有行概念
12.2 文件定位:linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文本文件,但不能读写二进制文件。用fread和fwrite可以读写文本文件和二进制文件
文件内部有一个位置指针,用来指向当前读写的位置,也就是读到第几个字节。在文件打开时,如果打开模式是r和w
,位置指针指向文件的第一个字节。如果打开模式是a
,位置指针指向文件的尾部,每当从文件里读n个字节或文件里写入n个字节后,位置指针会后移n个字节。
文件位置指针与C中指针不是一回事,位置指针仅仅是一个标志,表示文件读写到的位置即读写到第几个字节,不表示地址。文件每读写一次,位置指针就会移动一次,不需要你在程序中定义和赋值,由系统自动设置。
os中存在内存缓冲区,调用fprintf、fwrite等函数往文件写入数据时,数据并不会立马写入磁盘文件,而是先写入缓冲区,等缓冲区满了后再写入文件,还有程序调用了fclose或fflush库函数时会把缓冲区数据写入文件。
#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);
13.编译预处理:C源程序 - 编译预处理【对预处理指令即以#开头指令和特殊符号进行处理,删除程序中注释和多余空白行】- 编译
条件编译:最常用的两种格式#ifdef和#ifndef 。#undef :取消已定义的标识符
如下book145.c和_public.c都有 #include"_public.h",会重复包含。
在_public.c中如下这样写,_public.h就不会被重复包含。
14.gdb调试:set args,b/r,n/s
多进/线程中无法用gdb调试,还是用printf,但不会把结果显示到界面,写入日志文件中。root 用户:yum -y install gdb,gdb -v。
15.makefile文件:依赖文件功能
make是一个命令工具,是一个解释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编译不链接。
16.多线程:pthread_create(),查看线程top -H,ps -xH | grep
16.1 子线程未执行:join
如下线程thread
和进程process
区别:process不能共享内存。
如下线程主函数void* 。pthread_create的第四个参数是myfunc的参数。
如上没有打印出hello word,如下join等待进行改进。
16.2 线程传参区分线程:“th1”
如下改进上面,往线程里传参区分线程。
16.3 两子线程数字相加:分别加到自己线程变量中
写两条线程将5000个数字加起来。
如下解决上面代码重复太多问题,将0-2500和2500-5000当参数传进来。
16.4 两个线程同时加到一个全局变量s中:5000数字小不会影响
不用每个线程的result。
16.5 全局变量S++要加锁:数字大出现race condition
如下每一条线程加1000000,两条线程应该为2000000。解决就是加锁。
如下t是时间,r读,w写。
解决:pthread_mutex_t 结构体,如下一共做了10万次加锁和解锁(时间太长),一段代码前后都要加解锁才能原子性。
如下从时间上看两个for循环各自独立存在(相当于单线程),不如写两个for循环在同一个线程里,这样还省去了4次加锁解锁时间。这就是前面把大数组拆成两段,两个线程分别加自己内容,最后放入main中加起来,这样不会race condition,也不需要通过锁解决。
16.6 假共享:两线程分别加到自己result数组中
0和1两个线程,两个result数组。
如下定义s为局部变量 = 结构体取出result,比上面要快。
如上完整,如下example6始终比example5快,将50000000多加一个0,快的更多。
为什么example6会比5快 ? 因为假共享false sharing。如下是单核cpu不会false sharing。
如下多核+运算结果距离近
:example5里result变量在线程主函数外,cpu线程计算要从RAM中拉取。example6里的s为局部变量放在两个线程主函数里即cpu缓存里做计算,cpu两个核里两个缓存不会互相影响。所以example6不会falsing sharing,速度快。
如下解决假共享:cache短,RAM里很长,第一个线程结果保存在0位置,第二个线程结果保存在100位置,cache只更新自己长度的一小段如下4段(空间换时间)。
如下id即0和1,是两个线程的id。线程0存0位置,线程1存100位置。
相关文章:
【C1】数据类型,常量变量,输入输出,运算符,if/switch/循环,/数组,指针,/结构体,文件操作,/编译预处理,gdb,makefile,线程
文章目录1.数据类型:单双引号,char(1B),int/float(32位系统,大小一样4B,但存储方式不同),double(8B),long double…...
【深度学习】pytorch的基础操作
import torch import numpy as np # 1.1 根据已有的数据创建张量 def test01(): # 1.1 创建标量 data torch.tensor(10) print(data) # 1.2 使用numpy数组来创建张量 data np.random.randn(2,3) data torch.tensor(data) print(data) # 1.3使用list…...
MWORKS--同元软控MWORKS介绍、安装与使用
MWORKS--同元软控MWORKS介绍、安装与使用1 同元软控介绍1.1 同元软控简介1.2 同元软控发展历史2 MWORKS介绍2.1 MWORKS简介2.2 MWORKS产品描述3 装备数字化3.1 发展3.2 内涵3.3 系统模型发展成为产品的一部分3.4 MWORKS系统模型数据管理3.4 MWORKS为装备数字化提供的套件4 下载…...
Python 解决dilb和face_recognition第三方包安装失败
目录 dilb和face_recognition第三方包安装失败 亲测有效的解决方法:whl安装方式 dilb和face_recognition第三方包安装失败 场景复现:因为需要用到dlibface_recognition,基于OpenCV做一些人脸识别的项目,在Pycharm中进行pip清华…...
Mac系统Mysql的8.0.22版本安装笔记和密码重置修改密码等问题方法
忘记密码官网教程地址:https://dev.mysql.com/doc/refman/5.7/en/resetting-permissions.html 5.7数据库安装指南参考:https://jingyan.baidu.com/article/fa4125ac0e3c2928ac709204.html 初次安装8.0.22遇到许多坑,密码修改失败;…...
驱动 | Linux | NVMe 不完全总结
本文主要参考这里 1’ 2 的解析和 linux 源码 3。 此处推荐一个可以便捷查看 linux 源码的网站 bootlin 4。 更新:2022 / 02 / 11 驱动 | Linux | NVMe 不完全总结NVMe 的前世今生从系统角度看 NVMe 驱动NVMe CommandPCI 总线从架构角度看 NVMe 驱动NVMe 驱动的文件…...
一个测试人员,在现阶段的环境下如何在测试行业发展和自我价值。
前言周末和几个测试圈子里的大佬饭局上聊了一些职场和测试职业发展相关的话题,我将聊天的内容做了整理和阐述。。朋友圈有测试同学对这篇文章提了比较深刻的建议,下面是他的评价和建议:评价:据说是大佬饭桌总结,有两点…...
pwn手记录题2
fastbin_reverse_into_tcache(2.34) 本题所使用的libc版本为2.34;(最新版 libc2.34版本已经没有了所谓的hook函数,甚至exit_hook(实际为某个函数指针)也已经不能够使用;能够利用的手法已经很少了; 高版本glibc堆的几…...
CSS ~ 从入门到入坑。
CSS ~ 从入门到入坑。 文章目录CSS ~ 从入门到入坑。what。css 三种实现方式。选择器。id 选择器 > class 选择器 > 标签选择器。标签选择器。类选择器。id 选择器。层次选择器。后代选择器。子选择器。相邻兄弟选择器。通用选择器。结构伪类选择器。属性选择器。字体风格…...
成都哪家机构的Java培训比较好,求一个不坑的?
关于这个问题,相信你会得到很多条答案,以及很多家机构的自荐。既然如此,不如也了解一下老牌IT职业教育机构:有足够丰富的教学经验,丰富的教学产品资源以及成熟的就业保障体系,还有就是承担风险的能力。 很…...
《爆肝整理》保姆级系列教程python接口自动化(十二)--https请求(SSL)(详解)
简介 本来最新的requests库V2.13.0是支持https请求的,但是一般写脚本时候,我们会用抓包工具fiddler,这时候会 报:requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590) 小编…...
离线数据仓库
1 数据仓库建模 1.1 建模工具 PowerDesigner/SQLYog/EZDML… 1.2 ODS层 (1)保持数据原貌不做任何修改,起到备份数据的作用。 (2)数据采用压缩,减少磁盘存储空间(例如:压缩采用LZO&…...
【前端】Vue项目:旅游App-(23)detail:房东介绍、热门评论、预定须知组件
文章目录目标过程与代码房东介绍landlord热门评论HotComment预定须知Book效果总代码修改或添加的文件detail.vuedetail-book.vuedetail-hotComment.vuedetail-landlord.vue参考本项目博客总结:【前端】Vue项目:旅游App-博客总结 目标 根据detail页面获…...
JUC并发编程与源码分析
一、本课程前置知识及要求说明 二、线程基础知识复习 三、CompletableFuture 四、说说Java"锁"事 8锁案例原理解释: 五、LockSupport与线程中断 六、 Java内存模型之JMM 七、volatile与JMM 八、CAS 九、原子操作类之18罗汉增强 十、聊聊ThreadLocal 十一、Java对…...
Spark09: Spark之checkpoint
一、checkpoint概述 checkpoint,是Spark提供的一个比较高级的功能。有时候,我们的Spark任务,比较复杂,从初始化RDD开始,到最后整个任务完成,有比较多的步骤,比如超过10个transformation算子。而…...
《剑指offer》:数组部分
一、数组中重复的数字题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1…...
基于微信小程序图书馆座位预约管理系统
开发工具:IDEA、微信小程序服务器:Tomcat9.0, jdk1.8项目构建:maven数据库:mysql5.7前端技术:vue、uniapp服务端技术:springbootmybatis本系统分微信小程序和管理后台两部分,项目采用…...
剑指 Offer Day1——栈与队列(简单)
本专栏将记录《剑指 Offer》的刷题,传送门:https://leetcode.cn/study-plan/lcof/。 目录剑指 Offer 09. 用两个栈实现队列剑指 Offer 30. 包含min函数的栈剑指 Offer 09. 用两个栈实现队列 原题链接:09. 用两个栈实现队列 class CQueue { pu…...
详解Python正则表达式中group与groups的用法
在Python中,正则表达式的group和groups方法是非常有用的函数,用于处理匹配结果的分组信息。 group方法是re.MatchObject类中的一个函数,用于返回匹配对象的整个匹配结果或特定的分组匹配结果。而groups方法同样是re.MatchObject类中的函数&am…...
Spring面试重点(三)——AOP循环依赖
Spring面试重点 AOP 前置通知(Before):在⽬标⽅法运行之前运行;后置通知(After):在⽬标⽅法运行结束之后运行;返回通知(AfterReturning):在⽬标…...
计算机网络之HTTP04ECDHE握手解析
DH算法 离散读对数问题是DH算法的数学基础 (1)计算公钥 (2)交换公钥,并计算 对方公钥^我的私钥 mod p 离散对数的交换幂运算交换律使二者算出来的值一样,都为K k就是对称加密的秘钥 2. DHE算法 E&#…...
【MySQL数据库】主从复制原理和应用
主从复制和读写分离1. 主从复制的原理2. 主从复制的环境配置2.1 准备好数据库服务器2.2 配置master2.3 配置slave2.4 测试3. 主从复制的应用——读写分离3.1 读写分离的背景3.2 Sharding-JDBC介绍3.3 Sharding-JDBC使用步骤1. 主从复制的原理 MySQL主从复制是一个异步的过程&a…...
复现随记~
note(美团2022) 比较简单的越界漏洞,堆本身并没有什么漏洞,而且保护并没全开,所以逆向思维。必然是ROP类而非指针类,故我们着重注意unsigned int等无符号数前后是否不一致 int __fastcall edit(__int64 a1) {int idx; // [rsp14…...
【计组】设计大型DMP系统--《深入浅出计算机组成原理》(十四)
目录 一、DMP:数据管理平台 二、MongoDB 真的万能吗 三、关系型数据库:不得不做的随机读写 (一)Cassandra:顺序写和随机读 1、Cassandra 的数据模型 2、Cassandra 的写操作 3、Cassandra 的读操作 (…...
66 使用注意力机制的seq2seq【动手学深度学习v2】
66 使用注意力机制的seq2seq【动手学深度学习v2】 深度学习学习笔记 学习视频:https://www.bilibili.com/video/BV1v44y1C7Tg/?spm_id_from…top_right_bar_window_history.content.click&vd_source75dce036dc8244310435eaf03de4e330 在机器翻译时,…...
NextJS(ReactSSR)
pre-render: 预渲染 1. 静态化 发生的时间:next build 1). 纯静态化 2). SSG: server static generator getStaticProps: 当渲染组件之前会运行 生成html json //该函数只可能在服务端运行 //该函数运行在组件渲染之前 //该函数只能在build期间运…...
JointBERT代码复现详解【上】
BERT for Joint Intent Classification and Slot Filling代码复现【上】 源码链接:JointBERT源码复现(含注释) 一、准备工作 源码架构 data:存放两个基准数据集;model:JointBert模型的实现;…...
进程间通信(上)
进程间通信(上)背景进程间通信目的进程间通信发展进程间通信分类管道什么是管道匿名管道实例代码简单的匿名管道实现一个父进程控制单个子进程完成指定任务父进程控制一批子进程完成任务(进程池)用fork来共享管道站在文件描述符角…...
【Unity3D】Unity 3D 连接 MySQL 数据库
1.Navicat准备 test 数据库,并在test数据库下创建 user 数据表,预先插入测试数据。 2.启动 Unity Hub 新建一个项目,然后在Unity编辑器的 Project视图 中,右击新建一个 Plugins 文件夹将连接 MySQL的驱动包 导入(附加驱…...
vue通用后台管理系统
用到的js库 遇到的问题 vuex和 localStorage区别 vuex在内存中,localStorage存在本地localStorage只能存储字符串类型数据,存储对象需要JSON.stringify() 和 parse()…读取内存比读取硬盘速度要快刷新页面vuex数据丢失,localStorage不会vuex…...
80 wordpress/营销推广渠道有哪些
Lora 数据发送与接收 预计到2025年,我们将有250亿台设备连接到互联网。 相当于今天的地球人口多三倍。 随着物联网和工业4.0的概念,互联车辆和智能城市的迅速普及,这种情况最有可能发生。 我们已经有少数无线协议,如BLE、Wi-Fi、蜂窝等,但是这些技术对于IoT传感器节点而言…...
做网站有生意吗/seo还能赚钱吗
1、目标今天的目标是某生鲜App的签名 paramsMD5 ,抓个包先:javaTIP: 新鲜热乎的 1.4.5python2、步骤老规矩,上jadx纳尼...... 这个 qihoo 很眼熟,在Windows平台下是老熟人了,没想到如今混移动端了,它又冒出…...
专做外贸的网站有哪些/怎么做产品推广平台
JDK版本:1.7update65 Eclipse版本:Juno Service Release 2(4.2.2) 首先在Eclipse中安装Axis2的插件: 1,下载Axis2插件,最新版本为1.6.2:http://www.apache.org/dyn/mirrors/mirro…...
香港网站服务器/91永久免费海外地域网名
假设我们有一个0和1的数组A,考虑N [i]是从索引A [0]到A [i]的第i个子数组,被解释为二进制数。我们必须找到一个布尔答案列表,其中且仅当N [i]被5整除时,答案[i]为真。因此,如果输入类似于[0,1,1,1,1,1,1],则…...
2015年做那些网站能致富/产品推广渠道
1.Jdk Linux(Centos)安装Java JDK及卸载 2.Tomcat (开机自启动) Linux(Centos)安装tomcat并且部署Java Web项目 3.CentOS7.3搭建ApachePHP7web SVNMariaDB Web服务器(2017-10-24) CentOS7.3搭建ApachePHP7web SVNMariaDB Web服务器(2017-10-2…...
网站建设的硬件支持/北京seo收费
[飞鸟各投林] 为官的家业雕零,富贵的金银散尽。有恩的死里逃生,无情的分明报应。欠命的命已还,欠泪的泪已尽:冤冤相报自非轻,分离聚合皆前定。欲知命短问前生,老来富贵也真侥幸,看破的遁入空门…...