这是一种保证指针指向的内容不会被改变的方式。这也是一种无需显式强制转换即可抑制警告的方法。
考虑一下:
void dash(char *str) // Removed const
{
// Code
}
int main() {
const char p[] = "this is a test";
dash(p);
}
现在编译器会发出这个:
k.c: In function ‘main’:
k.c:23:10: warning: passing argument 1 of ‘dash’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
23 | dash(p);
| ^
k.c:4:17: note: expected ‘char *’ but argument is of type ‘const char *’
4 | void dash(char *str)
| ~~~~~~^~~
由于您没有写信给它,因此无需担心此警告。但最好避免警告。在这种情况下,我们有两种选择。该函数可以修改字符串,也可以不修改。如果它无法修改它,那么就没有理由向编译器和读者解释确实如此。
旁注。字符串文字,如@987654324@,如果你修改它们会有未定义的行为,所以程序可能会崩溃(或不崩溃)。但是,它们的类型是 (char*) 类型,没有 const。原因是向后兼容。在 C++ 中,它们的类型是 const char*
请注意,const 是约定俗成的承诺,而不是编译器的承诺。此代码将修改原始字符串并编译时不会出现警告:
#include <stdio.h>
void foo(const char *str)
{
// Casting comes with great responsibility
// You're just saying to the compiler
// "Trust me and shut up"
char *ptr = (char*) str;
ptr[2]='A';
ptr[3]='T';
}
int main()
{
const char p[] = "this is a test";
foo(p);
puts(p);
}
输出:
$ ./a.out
thAT is a test
正如我所说,上面的代码将在没有警告的情况下编译。如果你移除演员表,你会得到这个:
k.c:5:17: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
5 | char *ptr = str;
| ^~~
请注意,由于p 被声明为const,这是未定义的行为。但是,您改为这样写main:
int main()
{
char p[] = "this is a test";
foo(p);
puts(p);
}
那么,程序是完全有效的。即使您将可写字符串传递给函数foo,您也希望它不会改变,因为foo 将常量指针作为参数。但是如你所见,这样的事情是可以绕过的。
小心使用空指针
请注意,这对于任何类型 T 都是完全有效的:
T x;
T *p;
p = (void*) &x;
这是因为您可以安全地将指针转换为 void 并返回。但是,这在一般情况下无效:
T x;
Q *p;
p = (void*) &x;
但是,由于演员阵容,您不会收到警告。但是这段代码调用了未定义的行为。
道德课
强制转换不是警告的 goto 解决方案。相反,你应该仔细考虑你的演员是否符合你的意图。如果您的意图是摆脱警告,正确的解决方案是删除参数的const。如果您打算添加演员表是“我知道这个函数承诺不会修改参数,但我有充分的理由承诺并立即打破该承诺”,那么演员表是正确的。
现实世界的例子
只是举一个真实世界的例子来说明它是如何出错的。我在this question 中看到了这个:
void * func_return();
void (*break_ptr)(void) = (void *)func_return;
我告诉 OP 演员阵容是错误的。我得到的回应是,如果没有演员表,编译器就会抱怨。好吧,它抱怨是因为指针错误。函数原型声明了一个函数,该函数采用未指定数量的参数并返回一个 void 指针。函数指针是一个指向不带任何参数的函数的指针。所以在这种情况下,正确的指针声明和初始化应该是这样的:
void * func_return();
void *(*break_ptr)() = func_return;
但这可能会更好:
void * func_return(void);
void *(*break_ptr)(void) = func_return;
请注意,任何类型的指针都可以安全地转换为void* 并返回。但在这种情况下,OP 并没有将其退回,而是转换为另一种类型。如果 OP 做得正确,演员表会很混乱,但在这种情况下,它确实隐藏了 REAL 错误。