C 使用常量限定符的一致性
似乎C 使用常量限定符的一致性,c,C,似乎const限定符经常被不一致地使用。下面是另一个答案的示例: 在函数不修改(或释放)指向的数据的情况下,始终对通过引用传递的函数参数使用常量 int find(const int *data, size_t size, int value); …其他用途是可选的。例如,函数实现中函数的参数可以标记为const 那么,在上述情况下,为什么会是这样而不是这样,例如: int find(const int *data, const size_t size, const int value)
const
限定符经常被不一致地使用。下面是另一个答案的示例:
- 在函数不修改(或释放)指向的数据的情况下,始终对通过引用传递的函数参数使用常量
…其他用途是可选的。例如,函数实现中函数的参数可以标记为constint find(const int *data, size_t size, int value);
int find(const int *data, const size_t size, const int value);
int find(const int *data, size_t size, int value);
...
int t[100]={ ... };
int pos=find(t, 100, 123);
// I'm certain t[] still contains the initial values
// (except in case of an ugly const-cast, but in such
// a case no one could ever trust anything...)
int find_A(const int *data, const size_t size, const int value);
int find_B(const int *data, size_t size, int value)
{
size-=10; // stupid, just for the sake of the example
value+=5; // stupid, just for the sake of the example
...
}
...
int t[100]={ ... };
size_t sz=100;
int val=123;
int pos_A=find_A(t, sz, val); // sz and val won't be mutated
int pos_B=find_B(t, sz, val); // sz and val will no more be mutated
或:
似乎95%或更多的时候,参数不会被修改。例如,如果我有一个数学程序(或任何与此相关的函数),参数是否都是:
int add_five_numbers(const int num1, const int num2, const int num3, ...)
或者什么时候使用
const
限定符有意义,什么时候只是冗长?const
应该用于作为调用方数据指针的参数,而指针不应该修改该数据。这称为常量正确性
并不是说const正确性不仅仅是一个自我记录代码或防止编写函数的程序员意外失误的问题,它还可以帮助编译器优化指针别名。如果编译器知道指针参数不能修改,例如某些外部链接变量,它可以在代码生成过程中排除这种情况,可能会导致更快的代码
通过valueconst
传递参数的意义要小得多,因为所有参数都是本地副本,并且不能在调用方修改原始值
有些人出于某种原因采用了一种编码方式,他们也使用传递值参数
const
,并编写类似const int-value
的内容。这样做没有好的理由。与指针不同,这只是主观编码风格的问题。首先,在指针参数上使用const
非常有帮助,因为它为调用站点提供了承诺。
例如:
int find(const int *data, const size_t size, const int value);
int find(const int *data, size_t size, int value);
...
int t[100]={ ... };
int pos=find(t, 100, 123);
// I'm certain t[] still contains the initial values
// (except in case of an ugly const-cast, but in such
// a case no one could ever trust anything...)
int find_A(const int *data, const size_t size, const int value);
int find_B(const int *data, size_t size, int value)
{
size-=10; // stupid, just for the sake of the example
value+=5; // stupid, just for the sake of the example
...
}
...
int t[100]={ ... };
size_t sz=100;
int val=123;
int pos_A=find_A(t, sz, val); // sz and val won't be mutated
int pos_B=find_B(t, sz, val); // sz and val will no more be mutated
此外,假设您有:
const int *t=...;
int pos=find(t, 100, 123);
如果find()
的第一个参数是const int*data
,则此调用是正确的,但如果此参数是int*data
,则该调用将被拒绝,因为该函数能够变异指向的数据(即使它没有),但是t
变量不允许对指向的数据进行变异
现在,当涉及到传递简单类型(通过值)时,参数将被修改或不在函数中这一事实在调用站点不会改变任何东西;它只是函数本身的一个实现细节,所以没有必要让原型更难阅读。
例如:
int find(const int *data, const size_t size, const int value);
int find(const int *data, size_t size, int value);
...
int t[100]={ ... };
int pos=find(t, 100, 123);
// I'm certain t[] still contains the initial values
// (except in case of an ugly const-cast, but in such
// a case no one could ever trust anything...)
int find_A(const int *data, const size_t size, const int value);
int find_B(const int *data, size_t size, int value)
{
size-=10; // stupid, just for the sake of the example
value+=5; // stupid, just for the sake of the example
...
}
...
int t[100]={ ... };
size_t sz=100;
int val=123;
int pos_A=find_A(t, sz, val); // sz and val won't be mutated
int pos_B=find_B(t, sz, val); // sz and val will no more be mutated
实际上,在调用find_B()
(或find_A()
)size
和value
时,都是sz
和val
的副本;这些副本可能会发生变异,这将永远不会改变原始变量。
此外,据我所知,const
参数在声明中被忽略(不在定义中);i、 你可以定义
int find(const int * const data, const size_t size, const int value)
{
...
}
并提供该声明是否
int find(const int * const data, const size_t size, const int value);
还是这个
int find(const int *data, size_t size, int value);
它不会改变呼叫站点上的任何内容
还要注意,当再次考虑指针参数时,同样的考虑也适用。
星号前的const
表示指针指向的数据不能突变,这非常重要且有意义,但星号后的const
表示指针本身不能突变(即初始化后不能指向其他对象)。
例如,使用const int*const data
时,您不能执行*data=8
(前导const
),也不能再执行++data
(尾随const
)。
另一方面,使用const int*data
仍然无法执行*data=8
(前导const
),但允许执行++data
(无尾随const
)。
当然,最后一个操作不会移动调用站点上的任何指针(原因与size
和value
相同)
因此,最后,您应该只在指针参数上使用有意义的(前导)
const
限定符来声明指向的数据不会发生变化,因此,在限定数据上启用此函数。何时使用常量限定符有意义?
回答:在函数不修改(或释放)指向的数据的情况下,对通过引用传递的函数参数使用常量。
在其他情况下,何时只是冗长?
,当通过值传递参数时。@KamilCuk这是否意味着只需要在函数中的数组/指针参数上添加const
?因此函数(const int arr[],const int*ptr,int x)
如果三个参数都没有修改,或者…?函数(const int arr[])
和函数(const int*arr)
完全相同。是的,在C中,使用指针传递值意味着通过引用它来传递参数。参数是通过C中的值来传递的。因此,将const
应用到该值的副本只是一个冗长的过程。通过指定参数const
可以限制在函数体中使用它可以做什么。通过将data
指定为const int*
可以说data
是指向const int
的指针。这意味着,虽然允许您更改数据
,但不允许您更改数据所指向的目标。相比之下,将其指定为int*const
,这意味着它指向的内容是可修改的,但指针本身不是。您现在可以分配,但不能执行++data
(如果数据是const int*
,则可以执行此操作)。因为函数接收的是size\u t size,int value
的副本,所以