查看代码时,我遵循以下规则:
const
当函数不修改(或释放)所指向的数据时,请始终用于通过引用传递的函数参数。
int find(const int *data, size_t size, int value);
始终const
用于可能使用#define或枚举定义的常量。结果,编译器可以将数据定位在只读存储器(ROM)中(尽管在嵌入式系统中,链接器通常是用于此目的的更好的工具)。
const double PI = 3.14;
切勿在函数原型中对通过value传递的参数
使用const 。它没有意义,因此只是“噪音”。
// don't add const to 'value' or 'size'
int find(const int *data, size_t size, const int value);
在适当的const volatile
地方,在程序无法更改但仍可能更改的位置上使用。硬件寄存器是此处的典型用例,例如反映设备状态的状态寄存器:
const volatile int32_t *DEVICE_STATUS = (int32_t*) 0x100;
其他用途是可选的。例如,函数实现中函数的参数可以标记为const。
// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)
{
... etc
或获得的函数返回值或计算结果,然后再不更改:
char *repeat_str(const char *str, size_t n)
{
const size_t len = strlen(str);
const size_t buf_size = 1 + (len * n);
char *buf = malloc(buf_size);
...
的这些用法const
只是表明您不会更改变量;它们不会更改变量的存储方式或位置。编译器当然可以确定变量没有更改,但是通过添加const
允许它强制执行。这可以帮助读者并增加一些安全性(尽管如果您的功能足够大或过于复杂以至于有很大的不同,则可以说还有其他问题)。编辑-例如 一个200行密集编码的函数,该函数带有嵌套循环和许多长的或相似的变量名,知道某些变量永远不会改变可能会大大简化其含义。此类功能设计或维护不当。
问题const
。您可能会听到“常量中毒”一词。当添加const
到函数参数导致“常数”传播时,会发生这种情况。
编辑-const中毒:例如在函数中:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
如果我们更改str
为const
,则必须确保fuction_b
还需要一个const
。依此类推,如果function_b
将继续传递str
给function_c
,等等。可以想象,如果它传播到许多单独的文件/模块中,可能会很痛苦。如果它传播到无法更改的功能(例如系统库),则必须进行强制转换。因此,散布
const
在现有代码中可能会带来麻烦。但是,在新代码中,最好const
在适当的情况下保持一致。
更为隐蔽的问题const
是它不是使用原始语言编写的。作为附加组件,它不太适合。首先,它有两个含义(如上述规则所示,意思是“我不会更改”和“无法修改”)。但是,除此之外,它还很危险。例如,编译并运行以下代码,并且(取决于编译器/选项)在运行时可能会崩溃:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';
strchr
返回char*
而不是const char*
。由于
const
必须将其调用参数强制转换为char*
。在这种情况下,这将放弃真正的只读存储属性。编辑:-这通常适用于只读存储器中的vars。“ ROM”不仅指物理ROM,还指任何写保护的内存,就像在典型OS上运行的程序的代码部分一样。
许多标准库函数的行为方式相同,所以要当心:当您拥有实常数(即存储在ROM中)时,必须非常小心,不要失去其常数。
Specific issues with software development
。我很具体。