我的理解是:如果函数的目的是修改输入参数代表的指针的值,则加 const 更安全;如果函数的目的是为了修改输入字符数组的内容,就不能加 const。
测试代码:
#include <stdio.h>
#include <string.h>
void parameter_no_qualifier_const_is_to_modify_chararray_contents(char** p_array);
void test__parameter_no_qualifier_const_is_to_modify_chararray_contents();
void parameter_with_qualifier_const_is_to_modify_pointer_value(const char** pp);
void test__parameter_with_qualifier_const_is_to_modify_pointer_value();
int main()
{
test__parameter_no_qualifier_const_is_to_modify_chararray_contents();
test__parameter_with_qualifier_const_is_to_modify_pointer_value();
return 0;
}
void parameter_no_qualifier_const_is_to_modify_chararray_contents(char** p_array)
{
// 如果函数参数形式为 const char** p_array,则下面紧跟的行会编译出错:
// error C2440: “初始化”: 无法从“const char *”转换为“char *”
char* array = *p_array;
*array++ = 'c';
*array++ = 'h';
*array++ = 'i';
*array++ = 'j';
*array++ = 'k';
*array = '\0';
// 或,以下面的方式改变数组各元素的值。
// 如果函数参数形式为 const char** p_array,则下面 4 行都会编译出错:
// error C3892: “p_array”: 不能给常量赋值
// (*p_array)[0] = 'c';
// (*p_array)[1] = 'h';
// (*p_array)[2] = 'i';
// (*p_array)[3] = 'j';
// (*p_array)[4] = 'k';
// (*p_array)[5] = '\0';
// (*p_array)++;
}
void test__parameter_no_qualifier_const_is_to_modify_chararray_contents()
{
char array[10] = {'a', 'e', 'f', '\0', 'x', 'y', 'z', '\0'};
printf("%s\r\n", array); // aef
char* p_array = array;
parameter_no_qualifier_const_is_to_modify_chararray_contents(&p_array);
printf("%s\r\n\r\n", array); // chijk
}
void parameter_with_qualifier_const_is_to_modify_pointer_value(const char** pp)
{
// pp 的类型是 const char**,即 char const**,非常量。因函数参数是按值传递,所以内部修改不影响原值。
// *pp 的类型是 const char*,即 char const*,非常量。函数内部可间接修改之。
// **pp 的类型是 const char,即 char const,常量。编译器禁止修改其值。
(*pp)++;
// **pp = 'Q'; // error C3892: “pp”: 不能给常量赋值
}
void test__parameter_with_qualifier_const_is_to_modify_pointer_value()
{
char* p = "AXY";
printf("%s\r\n", p); // AXY
// error C2664: “parameter_use_qualifier_const_is_to_modify_pointer_value”: 不能将参数 1 从“char **”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(&p);
// 可编译通过的 C 风格强制类型转换
parameter_with_qualifier_const_is_to_modify_pointer_value((const char**)&p);
printf("%s\r\n\r\n", p); // XY
char* p2 = "axy";
printf("%s\r\n", p2); // axy
// 等价且正确的 C++ 风格强制类型转换是用:const_cast
parameter_with_qualifier_const_is_to_modify_pointer_value(const_cast<const char**>(&p2));
printf("%s\r\n\r\n", p2); // xy
// char* p3 = "axy";
// error C2440: “static_cast”: 无法从“char **”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(static_cast<const char**>(&p3));
// char* p4 = "axy";
// error C2680: “const char **”: dynamic_cast 的目标类型无效
// parameter_with_qualifier_const_is_to_modify_pointer_value(dynamic_cast<const char**>(&p4));
// char* p5 = "axy";
// error C2440: “reinterpret_cast”: 无法从“char **”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(reinterpret_cast<const char**>(&p5));
// 如果是 char ()[],而不是 char*。那么,。。。
char p6[] = "DXY";
printf("%s\r\n", p6); // DXY
// error C2664: “parameter_with_qualifier_const_is_to_modify_pointer_value”: 不能将参数 1 从“char (*)[4]”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(&p6);
// 输入参数是数组情况下,还想修改指针的值,向上面那样就不行了(数组名的值是不能被修改的)。
// 可编译通过的 C 风格强制类型转换
parameter_with_qualifier_const_is_to_modify_pointer_value((const char**)(&p6));
printf("%s\r\n\r\n", p6); // EXY (?因为:'E' = 'D' + 1)
// 正确的做法是:
char* p6_ = p6;
printf("%s\r\n", p6_); // EXY
parameter_with_qualifier_const_is_to_modify_pointer_value((const char**)(&p6_));
printf("%s\r\n\r\n", p6_); // XY
// char p7[] = "dxy";
// error C2440: “const_cast”: 无法从“char (*)[4]”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(const_cast<const char**>(&p7));
// char p8[] = "dxy";
// error C2440: “static_cast”: 无法从“char (*)[4]”转换为“const char **”
// parameter_with_qualifier_const_is_to_modify_pointer_value(static_cast<const char**>(&p8));
// char p9[] = "dxy";
// error C2680: “const char **”: dynamic_cast 的目标类型无效
// parameter_with_qualifier_const_is_to_modify_pointer_value(dynamic_cast<const char**>(&p9));
char p10[] = "dxy";
printf("%s\n", p10); // dxy
// 可编译通过但错误的 C++ 风格强制类型转换是用:reinterpret_cast
parameter_with_qualifier_const_is_to_modify_pointer_value(reinterpret_cast<const char**>(&p10));
printf("%s\n\n", p10); // exy (?因为:'e' = 'd' + 1)
char* p10_ = p10;
printf("%s\n", p10_); // exy
parameter_with_qualifier_const_is_to_modify_pointer_value(const_cast<const char**>(&p10_));
printf("%s\n\n", p10_); // xy
}