我试图了解如何在C代码中使用const
。首先,我并没有真正使用它,但后来我看到了很多const
在整个过程中被使用的例子。我应该努力并回去并虔诚地制作合适的变量const
吗?或者我只是在等我的时间?
我认为这样可以更容易地读取预期会发生变化的变量,特别是在人类和编译器的函数调用中。我错过了其他重要的观点吗?
答案 0 :(得分:7)
const
是类型的,#define
宏不是。
const
由C块限定,#define
适用于文件(或更严格地说,编译单元)。
const
对参数传递最有用。如果您看到带有指针的原型上使用的const
,您知道传递数组或结构是安全的,因为该函数不会改变它。没有const
,它可以。
查看strcpy()
之类的定义,你会明白我的意思。在开始时将“const-ness”应用于函数原型。复古const
并不像“大量工作”那么困难(但如果你按小时收到工资,那就好了)。
还要考虑:
const char *s = "Hello World";
char *s = "Hello World";
这是正确的,为什么?
答案 1 :(得分:6)
How do I best use the const keyword in C?
如果您想要“只读”,请使用const
。就这么简单:)
答案 2 :(得分:2)
使用const
不仅是一种很好的做法,还可以提高代码的可读性和可理解性,并有助于防止出现一些常见错误。绝对要在适当的地方使用const。
答案 3 :(得分:1)
除了在尝试修改常量并将常量作为非常量参数传递时产生编译器错误(因此充当编译器防护)之外,它还使编译器可以执行某些优化,因为知道该值不会更改,并且因此,它可以缓存该值,而不必从内存中读取它,因为它不会更改,并且可以立即将其替换为代码。
C常量
const
和register
基本上与volatile
相反,并且使用volatile
将覆盖文件和块范围的const优化,以及register
的优化块范围。 const register
和register
将产生相同的输出,因为const在gcc C -O0的块范围内在C上不执行任何操作,并且在-O1及更高版本上是多余的,因此仅应用register
优化在-O0,并且从-O1开始是多余的。
#include<stdio.h>
int main() {
const int i = 1;
printf("%d", i);
}
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1
mov eax, DWORD PTR [rbp-4] //load from stack isn't eliminated for block-scope consts on gcc C unlike on gcc C++ and clang C, even though value will be the same
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
在这种情况下,对于-O0,const
,volatile
和auto
都产生相同的代码,只有register
不同c.f.
#include<stdio.h>
const int i = 1;
int main() {
printf("%d", i);
}
i:
.long 1
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR i[rip] //load from memory
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
pop rbp
ret
改为使用const int i = 1;
:
i:
.long 1
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov eax, 1 //saves load from memory, now immediate
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
pop rbp
ret
C ++常量
#include <iostream>
int main() {
int i = 1;
std::cout << i;
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1 //stores on stack
mov eax, DWORD PTR [rbp-4] //loads the value stored on the stack
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
leave
ret
#include <iostream>
int main() {
const int i = 1;
std::cout << i;
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1 //stores it on the stack
mov esi, 1 //but saves a load from memory here, unlike on C
//'register' would skip this store on the stack altogether
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
leave
ret
#include <iostream>
int i = 1;
int main() {
std::cout << i;
}
i:
.long 1
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR i[rip] //load from memory
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
#include <iostream>
const int i = 1;
int main() {
std::cout << i;
}
main:
push rbp
mov rbp, rsp
mov esi, 1 //eliminated load from memory, now immediate
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
如果未初始化const
(在文件作用域和块作用域中), C ++具有产生编译器错误的额外限制。 const
还具有内部链接,这是C ++上的默认链接。 volatile
仍会覆盖const
和register
,但const register
结合了C ++的两个优化。
尽管以上所有代码都是使用默认的隐式-O0进行编译的,但使用-Ofast进行编译时,const
仍然令人惊讶地对于C或C ++在clang或gcc上对于文件范围的{{1 }}。除非使用consts
,否则不会优化内存中的负载,即使未在代码中修改文件作用域变量。 https://godbolt.org/z/PhDdxk。