我更喜欢将const
修饰符添加到我编写的函数中的所有内置参数中。例如:
void foo(const int arg1, const double arg2);
对我来说比更好
void foo(int arg1, double arg2);
在代码审查后,我被告知const
修饰符在应用于整数和内置类型时会带来开销。这是真的吗?为什么?
谢谢,
它的开销并不比typedef
多。你的同事错了。
如果你想说服他,打印出这两种变体的分解,并向你的同事展示它们是相同的。
然而,将const
限定符添加到像这样的原始类型中是完全没有意义和徒劳的。不管怎样,它们都是复制的,修改它们没有害处。让他们惊愕是没有任何好处的。
const
没有开销,我想您的同事只是对它的使用感到困惑,因为它(不幸的是)并不常见。就我个人而言,我更喜欢const
尽可能多的局部变量,因为它增加了可读性。
当然,反驳总是很容易的,采用以下程序并使用汇编输出进行编译:
#include <stdio.h>
void foo1(int a, double b)
{
printf("Not const %d, %gn", a, b);
}
void foo2(const int a, const double b)
{
printf("Const %d, %gn", a, b);
}
int main()
{
for(int i = 0; i < 10; ++i)
{
foo1(i, 5.5 * i);
foo2(i, 12.8 * i);
}
return 0;
}
为这些函数生成的汇编代码完全相同(使用VS2010版本构建):
对于foo1
(不带const
说明符):
; 4 : {
push ebp
mov ebp, esp
; 5 : printf("Not const %d, %gn", a, b);
fld QWORD PTR _b$[ebp]
sub esp, 8
fstp QWORD PTR [esp]
push eax
push OFFSET ??_C@_0BC@FACFPKBC@Not?5const?5?$CFd?0?5?$CFg?6?$AA@
call DWORD PTR __imp__printf
add esp, 16 ; 00000010H
; 6 : }
对于foo2
(带有const
说明符):
; 9 : {
push ebp
mov ebp, esp
; 10 : printf("Const %d, %gn", a, b);
fld QWORD PTR _b$[ebp]
sub esp, 8
fstp QWORD PTR [esp]
push eax
push OFFSET ??_C@_0O@LOLEPDHC@Const?5?$CFd?0?5?$CFg?6?$AA@
call DWORD PTR __imp__printf
add esp, 16 ; 00000010H
; 11 : }
这不是真的。
独立于此,您不应该将const
放入函数声明中,因为它是一个实现细节:它只限定函数范围中的局部变量。所以你可以这样写:
double foo(unsigned int a, double b); // declaration
double foo(unsigned int const a, double b) // implementation
{
b *= a;
return bar(b); // silly example
}
在代码审查后,我被告知const修饰符在应用于整数和内置类型时会带来开销。这是真的吗?为什么?
你把代码交给谁审阅?初级程序员?
上述情况并非如此。恰恰相反。使用const可能会应用一些优化。
或者,更确切地说,我想不出为什么这是真的。const
所做的只是强制编译器检查您是否没有更改变量的值;但这是一个编译时检查。
1.假设我们使用的是与运行时性能或编译代码大小相关的"开销"的传统定义 不,那不是真的。
我想你/他们把const和通过引用混淆了。
您的意思是什么类型的开销?编译二进制文件的开销还是编译器的开销?我确信编译后的二进制文件对于您添加的第一个和第二个代码示例是相同的。对于编译器——也许。Const添加了必须在编译时检查的附加条件。
如果它强制您创建一个额外的局部变量,则会带来开销。
无常量
void foo(const int arg1, double arg2)
{
if (arg1 == 1)
arg2 += 5.0;
// use arg2
}
带常量
void foo(const int arg1, const double arg2)
{
double arg2Copy;
if (arg1 == 1)
arg2Copy = arg2 + 5.0;
else
arg2Copy = arg2;
// use arg2Copy
}
但这实际上取决于编译器。如果您担心开销,那么应该比较生成的代码。