顶级太阳 发表于 2022-12-31 16:54:32

s1e33关于变量的生存期和存储类型的疑问

在s1e32视频中,从8:55开始,小甲鱼使用一个例子讲解变量的静态存储期。当变量定义过程中,前面加了static后,局部变量具有静态存储期,在所在函数结束后不释放内存,一直到程序结束才释放。举例如下:
#include<stdio.h>

void func(void)
{
        static int count;
        printf("count=%d\n",count);
        count++;
}

int main (void)
{
        int i;
        for(i=0;i<10;i++)
        {
                func();
        }
return 0;
}

这个时候运行代码,将会获得如下的结果:

而定义过程中,将static int count;改为int count;将会出现不同结果。

但是我在自己的虚拟机上尝试两次编程过程的时候,一直是第一个结果,

图片中间的vim命令上下分别是两次,带static和不带static的状态,结果是一样的。请问这是怎么回事?

lvk 发表于 2022-12-31 17:50:00

应该是没有初始化的问题,初始化一下就行了
int count = 0;

人造人 发表于 2022-12-31 17:50:42

main.c:5:5: warning: ‘count’ is used uninitialized [-Wuninitialized]

因为堆栈上面全是0,而且没有其他代码使用count这个变量的地址位置,所以一直保持上一次的值
所以才会出现 你截图的效果,我这边也和你的截图一样

让这个代码输出不正常,也非常容易,只需要把堆栈弄得乱七八糟就可以了
只需要随便调用上一个函数就可以了,下面的代码调用的是printf函数

sh-5.1$ cat main.c
#include <stdio.h>

void func(void) {
    int count;
    printf("count=%d\n", count);
    count++;
}

int main(void) {
    int i;
    for(i = 0; i < 10; i++) {
      printf("i=%d\n", i);         // 这个函数没有其他意思,就是为了弄乱堆栈,让堆栈中的值不再是0,不再保持之前的值
      func();
    }
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘func’:
main.c:5:5: warning: ‘count’ is used uninitialized [-Wuninitialized]
    5 |   printf("count=%d\n", count);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c:4:9: note: ‘count’ was declared here
    4 |   int count;
      |         ^~~~~
sh-5.1$ ./main
i=0
count=32538
i=1
count=32539
i=2
count=32540
i=3
count=32541
i=4
count=32542
i=5
count=32543
i=6
count=32544
i=7
count=32545
i=8
count=32546
i=9
count=32547
sh-5.1$

FengYue20 发表于 2022-12-31 17:50:43

你看看你的test.c是否保存修改了,不带静态是不可能会累加的!

人造人 发表于 2022-12-31 17:56:20

FengYue20 发表于 2022-12-31 17:50
你看看你的test.c是否保存修改了,不带静态是不可能会累加的!

sh-5.1$ cat main.c
#include <stdio.h>

void func(void) {
    int count;
    printf("count=%d\n", count);
    count++;
}

int main(void) {
    int i;
    for(i = 0; i < 10; i++) {
      func();
    }
    return 0;
}
sh-5.1$ gcc --version
gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘func’:
main.c:5:5: warning: ‘count’ is used uninitialized [-Wuninitialized]
    5 |   printf("count=%d\n", count);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c:4:9: note: ‘count’ was declared here
    4 |   int count;
      |         ^~~~~
sh-5.1$ ./main
count=0
count=1
count=2
count=3
count=4
count=5
count=6
count=7
count=8
count=9
sh-5.1$

FengYue20 发表于 2022-12-31 18:03:29

人造人 发表于 2022-12-31 17:56


大佬,能否看一下我这道题:https://fishc.com.cn/forum.php?mod=viewthread&tid=222692&page=1#pid6099234
为什么出了函数还能修改变量,不是应该弹栈了吗?

顶级太阳 发表于 2023-1-1 08:03:26

人造人 发表于 2022-12-31 17:56


那么也就是说,你这把gcc纠错开到最大,也只是出现了一个警告,对于程序的实际运行结果没有影响。那么这是为什么呢?

顶级太阳 发表于 2023-1-1 08:28:56

FengYue20 发表于 2022-12-31 17:50
你看看你的test.c是否保存修改了,不带静态是不可能会累加的!

反复确认过了,不带静态的时候发生了累加。所以才上来问的。刚刚学到这里,怕我哪里做的不对了。

人造人 发表于 2023-1-1 11:17:52

顶级太阳 发表于 2023-1-1 08:03
那么也就是说,你这把gcc纠错开到最大,也只是出现了一个警告,对于程序的实际运行结果没有影响。那么这 ...

?
3楼你看了吗?

顶级太阳 发表于 2023-1-3 08:06:47

人造人 发表于 2023-1-1 11:17
?
3楼你看了吗?

堆栈的事还不懂,以前没接触过这东西怎么弄。另外第3楼,每调用一次打印之外,输出的i值还是每调用一次增加1,没有出现调用后成为乱码呀。小甲鱼的例子很明显,每次调用函数的时候,count都会被重新置0,可是我的试验结果没有重置,你在第3楼的运行结果也显示了没有重新置0.

人造人 发表于 2023-1-3 12:08:15

顶级太阳 发表于 2023-1-3 08:06
堆栈的事还不懂,以前没接触过这东西怎么弄。另外第3楼,每调用一次打印之外,输出的i值还是每调用一次增 ...

编译器有点聪明,他会故意避开count的地址
我试了好多种方法,这样可以修改到count

sh-5.1$ cat main.c
#include <stdio.h>
#include <stdlib.h>

void fs(void) {
    int s = rand();
}

void func(void) {
    int count;
    printf("count=%d\n", count);
    count++;
}

int main(void) {
    int i;
    for(i = 0; i < 10; i++) {
      fs();
      func();
    }
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘fs’:
main.c:5:9: warning: unused variable ‘s’ [-Wunused-variable]
    5 |   int s = rand();
      |         ^
main.c: In function ‘func’:
main.c:10:5: warning: ‘count’ is used uninitialized [-Wuninitialized]
   10 |   printf("count=%d\n", count);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c:9:9: note: ‘count’ was declared here
    9 |   int count;
      |         ^~~~~
sh-5.1$ ./main
count=1804289383
count=846930886
count=1681692777
count=1714636915
count=1957747793
count=424238335
count=719885386
count=1649760492
count=596516649
count=1189641421
sh-5.1$

顶级太阳 发表于 2023-1-3 16:33:42

本帖最后由 顶级太阳 于 2023-1-3 16:34 编辑

人造人 发表于 2023-1-3 12:08
编译器有点聪明,他会故意避开count的地址
我试了好多种方法,这样可以修改到count

对于你写的这一段代码,我很不理解,每一次重新调用func函数的时候count应该是作为一个局部变量重新定义,这个时候应该是被置0的呀。
另外在做动动手第一个题目的时候,上面这个奇怪的问题又出现了。
#include<stdio.h>

void func1(void);
void func2(void);
char string1,string2;
int var1,var2;

int main(void)
{
        printf("add of func1:%p\n",&func1);
        printf("add of func2:%p\n",&func2);
        printf("add of string1:%p\n",&string1);
        printf("add of string2:%p\n",&string2);
        printf("add of global_var1:%p\n",&var1);
        printf("add of golbal_var2:%p\n",&var2);
        func1();
        func2();


return 0;
}

voidfunc1(void)
{

        static int param1,param2;
        printf("add of func1_param1:%p\n",&param1);
        printf("add of func1_parma2:%p\n",&param2);
        static int var1,var2;
        printf("add of func1_static_var1:%p\n",&var1);
        printf("add of func1_static_var2:%p\n",&var2);

}
voidfunc2(void)
{
        const int param1,param2;
        printf("add of func2_const_param1:%p\n",&param1);
        printf("add of func2_const_param2:%p\n",&param2);
        printf("add of func2_var1:%p\n",&var1);
        printf("add of func2_var2:%p\n",&var2);
}


小甲鱼的例子里,在func1里定义了两个参数param1和param2,查询了地址,在func2里将这两个参数const后,存储地址没有表。而我的代码两次调用后,存储地址改变了。我很纳闷。

人造人 发表于 2023-1-3 16:38:44

count应该是作为一个局部变量重新定义,这个时候应该是被置0的呀。
局部变量如果你没有主动初始化的话,是不会初始化的
#include <stdio.h>

int main(void) {
    int a = 3;      // a 初始化成3
    printf("%d\n", a);
    int b;          // b 没有初始化,值是随机的,有可能是0,也有可能是其他
    printf("%d\n", b);
    return 0;
}

顶级太阳 发表于 2023-1-3 16:57:38

人造人 发表于 2023-1-3 16:38
count应该是作为一个局部变量重新定义,这个时候应该是被置0的呀。
局部变量如果你没有主动初始化的话,是 ...

小甲鱼在s1e33的视频里9:37的时候明确说,变量被定义的时候,如果后面没有给出初始值的话,会被置0.
https://www.bilibili.com/video/BV17s411N78s?p=33&vd_source=41936c8e78c2cb4425915e72a8f708cb

dolly_yos2 发表于 2023-1-3 17:09:08

顶级太阳 发表于 2023-1-3 16:57
小甲鱼在s1e33的视频里9:37的时候明确说,变量被定义的时候,如果后面没有给出初始值的话,会被置0.
htt ...

我相信原文不是这么说的,或者有上下文。如果我猜错了,那小甲鱼就说错了。看看标准吧, http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf 的 6.7.10.11,看看是怎样规定的

人造人 发表于 2023-1-3 17:23:48

顶级太阳 发表于 2023-1-3 16:57
小甲鱼在s1e33的视频里9:37的时候明确说,变量被定义的时候,如果后面没有给出初始值的话,会被置0.
htt ...

学习就认真一点么
人家说的是静态局部变量,你可以再去听一遍
是加了static的局部变量才初始化成0
就是这样,少上两个字,意思就完全不一样了
少上一个字,其实意思就完全不一样了
例如 ‘不’ 字
局部变量和静态局部变量完全不一样

basketmn 发表于 2023-1-3 17:31:16

dolly_yos2 发表于 2023-1-3 17:09
我相信原文不是这么说的,或者有上下文。如果我猜错了,那小甲鱼就说错了。看看标准吧, http://www.open ...

大佬,你这些英文资料都是从哪找到?能不能分享下
谢谢

顶级太阳 发表于 2023-1-3 17:31:31

人造人 发表于 2023-1-3 17:23
学习就认真一点么
人家说的是静态局部变量,你可以再去听一遍
是加了static的局部变量才初始化成0


谢谢,这两节,接触了太多的关键字,对于这些有点乱,我再自己捋一捋。

顶级太阳 发表于 2023-1-3 17:31:57

dolly_yos2 发表于 2023-1-3 17:09
我相信原文不是这么说的,或者有上下文。如果我猜错了,那小甲鱼就说错了。看看标准吧, http://www.open ...

谢谢您的回复

dolly_yos2 发表于 2023-1-3 17:46:42

basketmn 发表于 2023-1-3 17:31
大佬,你这些英文资料都是从哪找到?能不能分享下
谢谢

这个资料就是 C 语言的标准(的 working draft),因为 C 语言的特点这应该是(除了正式的标准之外)最权威的 C 语言资料,所以涉及到这种语言本身的细节辨析就应该来这里找答案
直接搜索 C standard 就能找到了,还是很容易的
页: [1] 2
查看完整版本: s1e33关于变量的生存期和存储类型的疑问