ANSI C:指向字符串字面值的指针

4

可能是重复问题:
字符串字面值是const吗?

在ANSI C中,以下内容是否有效?

#include <stdio.h>

/* This returns "Hans" if arg != 0, "Gretel" if arg == 0 */
char* foo(int arg)
{
    return arg ? "Hans" : "Gretel";
}

int main()
{
    char* p_ch;

    p_ch = foo(1);
    printf("%s\n", p_ch);
    p_ch = foo(0);
    printf("%s\n", p_ch);

    return 0;
}

代码在GCC/Linux下编译和运行良好。
MinGW/Windows则提示:
invalid conversion from `const char*' to `char*'

MS Visual C/C++ 2008对该代码很好。

  1. 我能否在初始化点之外的其他地方将char*变量分配给文字字符串?
  2. 我已经阅读过字符串文字具有static分配类。这是否意味着它们在定义它们的函数之外是不可见的?
  3. const类型转换为其非const对应类型何时无效?

我会将foo声明为返回const char*。但是,当编译为C++时,代码变得无效。我不是足够的标准专家来精确解释为什么... 我本来期望GCC会发出一些警告(但即使使用-Wall -Wextra的gcc 4.6也没有)。 - Basile Starynkevitch
@Basile,因为gcc正在编译C代码。在C中做这件事情是_没有_问题的。如果你用g++编译它,那就另当别论了,但显然gcc不认为如果你尝试编译完全有效的C代码是有问题的。像“不能使用new变量名的警告,以防万一您将来可能想用C ++编译器编译此代码”这样的警告会令人恼火 :-) - paxdiablo
1
@BasileStarynkevitch:gcc -Wwrite-strings会给出相应的警告。这可能不是-Wextra的一部分,因为C库的某些部分可能依赖于此功能;例如,strerror具有返回类型char *,但可能使用字符串字面值的数组来实现。 - Fred Foo
感谢您提供的所有答案。 无论如何,由于字符串字面量属于“静态”分配类别,它们在函数foo()之外是否在技术上不可见? 是的,我知道,静态变量只是一个伪装的全局变量,因此它们存在直到程序终止,并且反过来,p_ch仍然是有效指针 - 但我能依赖这种行为吗? - peter.slizik
2个回答

6

是的,这是合法的C标准。但是,它之所以合法,是因为为了向后兼容,字符串字面量具有类型char[];出于安全考虑,你应该将foo的返回值设置为const char*。写入foo返回的任何一个字符串都会引起未定义行为。

如果你的编译器报错了,那么你可能错误地使用了C++编译器。在C++中,字符串字面量具有类型const char []。(如果将char*更改为const char*,你的程序神奇地变成了一个有效的C++程序。)

我能否将char*变量分配给初始化点之外的文字字符串?

你的意思是

char *p;
// do some other stuff
p = "literal";

? 是的,这是可能的。

我读到字符串字面值具有静态分配类。这是否意味着它们在定义它们的函数之外不可见?

您正在混淆静态分配和静态变量。您可以在另一个翻译单位中使用从 foo 返回的结果。

从const类型转换为其非const对应类型何时无效?

自从1989年引入 C 的 const 以来,它就有了明确的禁止转换。您必须显式地将 const 转换掉。


1

从MinGW/Windows编译器得到的错误信息强烈暗示您正在将此代码编译为C++。在C语言中,字符串字面值具有char[N]类型(与C++中的const char[N]相对)。在C语言中,您不应该收到此错误消息。尽管如此,在C中,字符串字面值也是不可修改的,这意味着指向字符串字面值时最好坚持使用const char *指针。

您的第一个问题有点奇怪。字符串字面值是无名对象,这意味着初始化是直接使指针指向字符串字面值的唯一方法。没有其他方法。稍后,您可以将非const指针复制到其他非const指针中,这是可以的。只需记住,您不能通过这些指针写入任何字符串字面值:字符串字面值是不可修改的。

你的第二个问题也没有太多意义。"可见性"是一个名称的属性。字符串字面量是无名对象。它们在任何地方都不可见。它们不能被看到,因为它们没有名称。由于它们没有名称,唯一的方法是在指针初始化期间附加指针以抓住字符串字面量并将其保留(如您的示例中所示)。可见性与此毫无关系。字符串字面量确实具有静态存储期,这意味着它们"永远存在":只要程序运行,它们就存在。在您的示例中,字符串字面量"Hans""Gretel"甚至在foo退出后仍然存在,这意味着foo返回的指针仍然有效。

对于您的第三个问题的答案是:在C语言中从const指针到非const指针的隐式转换从未存在过,即它始终是无效的。您必须使用显式转换才能执行此类转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接