这个static其实一点都不安静,这不,你得注意以下几点:
作用域只限于从定义处开始,到文件结尾处,即使你使用extern去申请也不管用的。
在函数体里定义,就只能在这个函数体里面使用,同一文件的其他的函数使用也是 不行的,由于被static修饰??的存放在内存的静态区,就是这个函数运行结束, 变量也不会被撤销。
#include<stdio.h>
static int j;
void fun1(void)
{
static int i = 0;
i ++;
printf("\n");
printf("static's i= %d\t",i);
}
void fun2(void){
j = 0;
j ++;
printf("\n");
printf("non-static j=%d\t",j);
}
int main(){
int k;
for(k = 0; k < 10; k++){
fun1();
fun2();
}
return 0;
}
下面是该段程序的运行结果:
static's i= 1 non-static j=1 static's i= 2
non-static j=1 static's i= 3 non-static j=1
static's i= 4 non-static j=1 static's i= 5
non-static j=1 static's i= 6 non-static j=1
static's i= 7 non-static j=1 static's i= 8
non-static j=1 static's i= 9 non-static j=1
static's i= 10 non-static j=1
从这里我们可以看出来,fun1()内的静态变量没有被释放,还是维持着 上次运行的结果。
这里的修饰,是应该它本来的面目,也就是指该函数只对该文件有效,这样, 不同的人在一个大型项目中不必担心命名冲突。linux kernel中充斥着大量的 static.
作用两个: 1) 对函数返回的限定 2) 对函数参数的限定
如果p1和p2的指针类型相同,我们可以在p1和p2之间相互赋值,如果P1和P2 指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的 指针类型转换为左边指针的类型。 例如:
float *p1;
int *p2;
p1 = p2;
最后一句是错误的,必须按照
p1 =(float *)p2;
来赋值。 但是不能将void类型的指针赋值给有类型的指针。
该标准规定不能对void类型的指针进行算法运算,因为不知道该指针的类型(存储空间)。 但是,GNU委员会不这么认为,它规定void * 的类型与char * 的类型一致。所以, 你想写出移植行很高的代码,需要进行如下的操作:
void *pvoid;
(char *)pvoid++;//ANSI: right
(char *)pvoid += 1; //ANSI: errors
很久之前接触过这个东西,这是很久的事情了。现在又是重新捡起来。
简单说一下,所谓的并查集,顾名思义,就是一个合并、查找的过程。 查找的过程相对简单点,合并的过程需要防止形成单链,理解起来可能有 点麻烦。
其实,很多时候都是自己的数据结构没有学好,连数据的存储形式都搞不明 白。这里我们用数组来模拟一下。
pre[i]
比如pre[3] = 15,就是3的前导点是15,当一个pre[i] == i的时候,就说明 它的前导点就是它自己了,这也是我们的一个过程。
int find(int x){
int r = x;
/*直到找到自己的前导点为自己*/
while(r != pre[r])
r = pre[r];
return r;
}
比如说,在一个集合内含有{1,2,3,4},”1” 为根节点,那么使用 __find(4)__都可以找到1,上面的代码的作用就是这样的.其实,从上面 介绍中,我们也可以看出,这是一棵树。在下面合并的过程中,如果只是 单单把根节点合并在一起,只有两个集合还可以,有很多个集合就会费很大 的力气。为此,我们在查找的过程中,可以适当做一些优化,这一步被成为 路径压缩。比如:
1 1---- / \ 优化成: /|\ | 2 5 ——————--> 2 4 5 6 / \ 4 6
利用上面的find
函数,找到了x的根节点,那么,我们可以认为在这个查
找的过程中,所经历的节点的根节点都是x的根节点,那么:
int find(int x){
int r = x;
while(r != pre[r])
r = pre[r];
int i, j = x;
while(r != pre[j]){
i = pre[j];
/*根节点赋值给经过路径上的节点*/
pre[j] = r;
j = i;
}
}
这一步就是将两个树形节点合并起来。
void union(int x, int y){
int tx = find(x);
int ty = find(y);
/*将y的前导点设置为x*/
if(tx != ty)
pre[ty] = tx;
}
来自hdu上的题目。连通点: 给定n个节点,m条边,接下来是m条边的两个端点,问只需要连接几条边,就可以将 所有的边连接起来且没有回路.
这道题目就是简简单单的问连通集的个数,连成一条线的话就再减去1.
#include<stdio.h>
int pre[1050];
int flags[1050];
int find(int x){
/* you must don't forget */
int r = x;
while(r != pre[r]){
r = pre[r];
}
int j = x, i;
while(pre[j] != r){
i = pre[j];
pre[j] = r;
j = i;
}
return r;
}
void mix(int a,int b){
int root_a = find(a);
int root_b = find(b);
if(root_a != root_b)
pre[a] = b;
}
int main()
{
int n,m,a,b;
int i,j;
freopen("find.in","r",stdin);
scanf("%d%d",&n,&m);
for(i = 1; i <= n; i++){
pre[i] = i;
/*将自己本身设为自己的前导点*/
flags[i] = 0;
}
for(j = 1; j <= m; j++){
scanf("%d%d",&a,&b);
mix(a,b);
}
for(i = 1; i <= n; i++){
flags[find(i)] = 1;
}
int ans = 0;
for(i = 1; i <= n; i++)
{
if(flags[i] == 1)
ans++;
}
printf("total ans is %d\n",ans - 1);
}
为了减少以后不必要的麻烦,这里暂时把时间日期打乱了,自己心里有数就行。[2016-09-27]
我是9月18号离的职,出来以后就回到学校,什么人也不想见,幸亏我的女朋友,陪我度过这一段糟糕的时间。
我居然二战了,内心是无比的复杂,今天就是这样,想起去年那些浪费的时间,自己就不能释怀了,自己做题也是 效率低的要命。
最要命的不是效率,而是我要报哪个学校?我想找一个与linux打交道的学校,为了两个人在一起,也可以去同一个 城市。
人啊,最怕的是欲望太多,或者说是幻想太强,在有一个领域里做不强,在其他领域里也是格外的痛苦。
我现在就是窝在学校南面的一个简易板房里发出的这篇博客,在以后的某段时间里,无论是开心还是失落, 时刻明白自己要的是什么,怎样去争取,而不能自暴自弃或者痴心妄想。
二战失败也是可以接受的,这只是你的生命里一条与他人不同的轨迹,在你忙着活命的时候,别人也是如此。
还有不到三个月的时间,努力忘掉自我,消失就对了。
生命不息。
这一周期在内核中至关重要,refer to the article
merge window
大约维持两周的时间,其实,如果我没记错的话,也就是最后一个rc释放出来
就是merge window
的开始时间。原话是这样说的:
The merge window lasts for approximately two weeks. At the end of this time, Linus Torvalds will declare that the window is closed and release the first of the “rc” kernels.
这里有一个与中文思维差异很大的命名方式,下面的原文:
or the kernel which is destined to be 2.6.40, for example, the release which happens at the end of the merge window will be called 2.6.40-rc1. The -rc1 release is the signal that the time to merge new features has passed, and that the time to stabilize the next kernel has begun.
2.6.40-rc1
一直到2.6.40-rc7
(反正最后一个rc)是为了2.6.41
准备的。那么,具体到什么版本的rcx作为stable
版本,
这里也没有一个确切的规定,一般是人为的认为bug最少(regression)。等到stable版本出来之后,就会选择其中的一个交给Greg HK维护。
stable
版本也会接受patch,但是必须接受以下两点:
1. 一个有效的bug fix;
2. patch已经合并到主线内核中
The selection of a kernel for long-term support is purely a matter of a maintainer
having the need and the time to maintain that release. There are no known plans for
long-term support for any specific upcoming release.
这句话的意思:长期版本的支持(long term)内核的选择,这对于维护人来说是需要花费时间去维护的。 对于任何即将发布的特定版本,没有已知的长期支持计划。
也就是说,你的patch是你需要的,但是stable没有支持,这就需要你ccing stable团队,将patch吸收进去, 而且,能不能成功,这也是一个未知数。
The merge window lasts for approximately two weeks. At the end of this time, Linus Torvalds will declare that the window is closed and release the first of the “rc” kernels. 这句话的意思是说,rc1的发布就意味着merge window的结束吧 但是,When the merge window opens, top-level maintainers will ask Linus to “pull” the patches they have selected for merging from their repositories. 这里,就感觉相互矛盾了呢。在git log中,随处可见子系统维护人tag 为rc3,rc4的pull请求,难道,merge window的开始时间不是最后一版的rc吗 ?
THe merge window is for kernel subsystem maintainers, as a “normal” developer, you usually don’t have to worry about that at all.
一个”rc”的持续时间大约一周,所以,一个次版本(minor version)的开发时间大约6~8周.
“rc1”的发布很关键。
这篇文章说的很清楚了。
—-»>
My question is about what to do during the closed window? I don’t think I should submit patches as I assume I’ll create a backlog for the maintainer who’ll possibly be flooded when the window re-opens. Similarly I could create patches but not send them until the window re-opens, but again I’ll just be creating a backlog.
Just keep going. The maintainers will keep a queue of patches and then try to apply them in order when the merge window -rc1 is released for the next one.
Worse cases would be that the patches will no longer apply (in which case, a V2 will be needed) or, if you haven’t heard anything for a while after the -rc1, then a patch RESEND should do the trick. —-«<
Hi Lucas,
To follow changes to the linux-tree tree you need to first do a remote update (this will get all the changes from the remote linux-next branch to the local origin/master tracking branch) and then reset the HEAD pointer of current checked out branch to the HEAD of linux-next remote tracking branch (i.e origin/master).
$ git remote update
$ git reset --hard origin/master
This will make your current branch (master) exactly like the remote linux-next tree. You cannot do pull or merge from the remote tracking branch.
SO 有关net net-next next-的解释。
next树包含的所有next树的信息在here
有许多向linus发送pull请求的git仓库并不一定在git.kernel.org网站,比如:
Merge tag ‘drm-fixes-2020-01-10’ of git://anongit.freedesktop.org/drm/drm
drm的tree就在freedesktop.org网站上。
I have given you an R-by for this one already, so why haven’t you added it here?
Reviewed-by: Rafael J. Wysocki [email protected]
什么意思呢?就是如果你在V2,V3,,,版本中一定加上此前别的hacker给你添加的R-by tags, 记住它
kernel的维护者,表面上很光鲜,其实他们的责任很大。
暂时先将lkml上看到的自己总结下来,每天看列表也是成为maintainer的基本功:)
在man calloc的手册中,我们可以看到是这么解释的.
给数组中的每一个元素分配一个内存,然后内存空间被设置为0.
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero. If nmemb or size is 0, then calloc() returns
either NULL, or a unique pointer value that can later be successfully
passed to free().
我们使用malloc和memset也是实现相同的东西
每一个新版本的发布需要两周的合并期,也就是linus从各个维护人那里得到新的特征 放进主线内核(mainline),两周之后,合并期关闭,然后被标记为”rc1”.在这期间, 不引入新的特征,只是对”rc1”的已有内容进行维护(修修补补),一周以后,”rc2”发布
这个过程一直维持到”rc7”,个别时期有可能是”rc6”或者”rc8”。当这一切到来时, 就会正式发布这个内核。比如,到了”4.5-rc7”,接下来,linus会发布”4.5”的正式版本。而对于”4.6”版本的开发周期又开始了.
> Fixes: d85b758f72b0 "virtio_net: fix support for small rings"
Fixes: d85b758f72b0 ("virtio_net: fix support for small rings")
后者才是正确的,被社区认可的。
When allocating memory, the GFP_KERNEL cannot be used during the
spin_lock period. It may cause scheduling when holding spin_lock
未证实这个论断的正确性,这里需要知道的知识点包括 内存分配的 标志 和 锁相关的原理和机制
内核提供机制,但不能在内核中提供策略。
比如所谈恋爱,内核不但可以允许我们谈恋爱,而且也不能限制我们和谁谈。 以前利用devfs实现的时候,第一个相亲的女孩为/dev/girl01,第二个相亲的女孩为 /dev/girl02,在udev的实现下,不管第几个女孩,统一称为/dev/mygirl.
/*
* netlink的使用规范,使用的udev
* 策略和机制的区别
*
* */
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<linux/netlink.h>
#include<poll.h>
static void die(char *s)
{
write(2, s, strlen(s));
exit(1);
}
int main(){
struct sockaddr_nl nls;
struct pollfd pfd;
char buf[512];
/*
* open hotplug event netlink socket
* */
memset(&nls, 0, sizeof(struct sockaddr_nl));
nls.nl_family = AF_NETLINK;
nls.nl_pid = getpid();
nls.nl_groups = -1;
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
if(pfd.fd == -1){
die("not root\n");
}
//listen to the netlink socket
if (bind(pfd.fd,(void *)&nls, sizeof(struct sockaddr_nl))){
die("Bind failure.\n");
}
while(poll(&pfd, 1, -1)){
/*
* wait something to happen
* */
int i, len = recv(pfd.fd, buf, sizeof(buf),MSG_DONTWAIT);
if(len == -1)
die("recv failed\n");
//print data to the stdout
i = 0;
while(i < len){
printf("%s\n",buf + i);/* char pointer */
i += strlen(buf + i) + 1; /* ?? */
}
}
die("poll\n");
return 0;
}
udev完全在用户态工作,利用设备加入或者移除时内核所发送的热插拔(hotplug)事件 来工作。在热插拔时,设备的详细信息通过netlink套接字发送出来,发出的事情叫做 uevent。 这段代码的实现了内核通过netlink接受热插拔事件并冲刷掉的范例.编译并运行这段 代码,然后插入usb或者其他热插拔事件,会在终端收到相关的信息.
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define LENGTH 100
int main()
{
int fd, len;
char str[LENGTH];
fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
/*
* creat and open file
* */
if(fd){
write(fd, "Hello,world",strlen("Hello,world"));
close(fd);
}
fd = open("hello.txt",O_RDWR);
len = read(fd, str, LENGTH);
/*
* str copied from file that should add '\0'
* */
str[len] = '\0';
printf("%s\n",str);
close(fd);
}
/*
* 上面的c语言函数是系统调用,这段代码是库函数的实现
* 从这里我们可以看出,库函数的文件操作的前面都有一个f,
* 这可能就是这两者最明显的区别了
* */
下面这是先向文件写内容,后来再读取文件中的内容。
#include<stdio.h>
#define LENGTH 100
int main()
{
FILE *fd;
char str[LENGTH];
fd = fopen("yubo.txt","w+");
if(fd){
fputs("Hello,yubo", fd);
/*Here, fputs write char into file */
fclose(fd);
}
fd = fopen("yubo.txt","r");
fgets(str,LENGTH,fd);
printf("%s\n",str);
fclose(fd);
}