我知道有很多这样的问题,但这个问题不是关于从C标准的Angular 来看static
和volatile
意味着什么,我感兴趣的是在汇编级别上发生的事情。
变量的static
关键字使这些变量静态可见(静态存储持续时间),就像全局变量一样。要使其成为真实的,编译器应该将这些变量写入.bss
节或其他地方?此外,static
关键字防止变量/函数在文件外部使用,是否仅在编译期间发生或有一些运行时检查?
变量的volatile
关键字使这些变量 * 从内存中读取 *,以确保如果其他东西(如外围设备)想要修改该变量,它将准确地看到该内存中的值。这里,“从内存中读取”的确切含义是什么?使用的内存位置是什么?.bss
、.data
还是其他东西?
谢谢!
2条答案
按热度按时间3b6akqbq1#
static
关键字有两层含义:(a)表示静态的存储类别,(B)表示内部的链接,这两种含义必须严格区分。具有静态存储类别的对象意味着它在程序开始时被分配,并一直存在到程序结束。这通常通过将对象放入数据段(对于初始化对象)或bss段(对于未初始化对象)来实现。详细信息可能因所讨论的工具链而异。
具有内部链接的标识符是指同一翻译单元中的每个标识符具有相同的名称和某种链接(即链接不是“none”)指的是与该标识符相同的对象。这通常是通过不使与标识符对应的符号成为全局符号来实现的。然后,接头将不会将来自不同翻译单位的相同符号识别为指相同符号。
volatile
关键字表示在抽象机中对volatile-qualified对象执行的所有操作都必须在生成的代码中执行。编译器不允许执行任何优化,因为这些优化会丢弃对volatile-qualified对象执行的任何此类操作,而对于non-volatile-qualified对象,编译器通常会这样做。此关键字纯粹是编译器的一个指令,用于抑制某些优化。它不影响这样限定的对象的存储类。有关此主题,请参阅my previous answer。
cu6pst1q2#
你也可以试试看
静态无符号整数x;无符号整数y;无符号整数z = 1;静态volatile无符号整数j;静态易失常量无符号整数k = 11;
孔隙函数(孔隙){ x = 5; y = 7; z ++ ; j+=2;
x在这样的例子中是不可能存在的,而且在任何文件中,它都可能出现在.bss中,因为我没有设置初始值。
y是.bss,符合预期
z为预期数据
volatile防止j被优化掉,尽管它是死代码/变量。
k可能以.rodata结尾,但在这里看起来像.data。
你们用的是花哨的词汇,但是C语言中的static仅仅意味着它的作用域局限于那个函数或文件。全局、局部、初始化与否、常量与否都会影响它是.data、.bss还是.rodata(如果你在链接器脚本中使用(rwx)的东西玩字母游戏,甚至会出现在.text而不是.rodata中)(建议:从不使用那些)。
volatile意味着不优化这个变量/操作,按照这个顺序做,不把它移出循环,等等。你可以找到关于它如何不是你所想的那样的讨论,我们在这个网站上看到llvm/clang和gnu/gcc对volatile的实际含义有不同的看法(当用于描述旨在访问外设中的控制或状态寄存器的指针时,基于volatile发明的一些参数(不是为了在中断和前台代码之间共享变量))。
就像static volatile不暗示它在哪个段一样,甚至可以和asm volatile(stuff)一起使用;告诉编译器我不希望你移动这段代码,我希望它按照这个顺序在这里发生。2(这是在变量上使用它的一个方面,或者我们是这么认为的)。
没有优化掉rodata、data或bss。
但是
多有趣啊,呃...让我们不要优化死代码,让我们把它放在那里。它不是全局的,没有人能看到它...
fun.c
so.c
链接的
每个x都是静态的,所以正如预期的那样,有两个x...嗯,预期是它们被优化了,但是...
它们是预期的.bss,因为我没有初始化它们。
在这方面
好吧,我终于有了一个. rodata。
对于单词和它们的(感知到的)定义,你能做的只有这么多,据我所知,这个主题是C与(生成的)asm。在某个时候,你应该实际尝试一下,你会发现它是多么微不足道,不需要编写复杂的代码。gcc,objdump,有时还有ld。嗯,我刚刚注意到在这种情况下,y从.rodata移动到了.data...这很有趣。
这只是尝试,它将测试编译器和其他工具作者的解释。比如register是什么意思volatile是什么意思,等等(并发现它像许多C语言(实现定义的)一样受到不同解释的影响)。有时知道你最喜欢的/特定的编译器对语言的解释是很重要的,但要非常注意实际实现定义的东西(位字段、联合体、结构体是如何构造的(打包它们会引起和它解决的问题一样多的问题)等等)...
到规范中去读任何定义,然后到你的编译器中去看他们是如何解释它的,然后回到规范中去看你是否能弄清楚它。
至于静态去本质上意味着范围,停留在函数或文件(良好的编译域为一个单一的编译操作).和volatile暗示请做这在这顺序并且请不要优化出这项目和/或它的操作.在这两种情况下,它是什么你使用他们与那决定他们在哪里.文本,.数据,.bss,.rodata,等.