免责声明:这个问题严格来说是学术性的。我即将给出的例子可能是糟糕的风格。
假设在C中我写了一个这种形式的子程序:
char *foo(int x)
{
static char bar[9];
if(x == 0)
strcpy(bar, "zero");
else
strcpy(bar, "not zero"),
return bar;
}
然后,在其他地方,我使用foo
如下:
printf("%i is %s\n", 5, foo(5));
我的指针和静态变量的心理模型预测,在实践中,这个printf的输出将是
5不为零
......但这是C标准实际要求的,还是我在鼻恶魔领域?
更糟糕的是,像
这样的事情strcpy(foo(5), "five");
我的心理模型说这应该"工作"除非它明确违法,但它有点无意义,因为它不会影响foo
的输出。但同样,这实际上是由标准定义的吗?
答案 0 :(得分:12)
你写的是好的;没有等待你的鼻子恶魔。即使strcpy()
示例也是'OK',因为您没有超越数组的范围。那个'OK'是引号,因为它不是一个好主意,但是如上所述,没有超出范围的内存访问,因此没有未定义的行为。函数中的static
数据贯穿整个程序的生命周期,包含写入它的最后一个值。
如果您尝试可能会出现问题:
printf("%i is %s but %i is %s\n", 5, foo(5), 0, foo(0));
你会得到两个数字之一的错误答案,但没有定义哪个是错误的答案。
答案 1 :(得分:5)
好吧,因为你想要标准的引用:
对象的生命周期是程序执行的一部分 在此期间保证为其保留存储空间。
一个对象,其标识符是在没有声明的情况下声明的 存储类指定_Thread_local,以及外部或内部链接 或与存储类指定静态,具有静态存储持续时间。的及其 生命周期是程序的整个执行及其存储的值 在程序启动之前只初始化一次。
答案 2 :(得分:2)
在任何条件下,foo()
都会返回一个指向静态变量的指针,该变量的生命周期是永久性的(即它从第一次控制经过它直到程序结束时开始生效)。这很好。
你的代码逻辑不太好;例如,该函数不是可重入的,远非线程安全的,当然无人看守的字符串操作是彻头彻尾的自杀。
答案 3 :(得分:1)
我认为这段代码没有任何问题。
foo()
返回的指针是一个有效的指针,你可以取消引用它。
编辑:通过“没有错”我的意思是一切都在语法上是正确的,但我同意其他答案,由于各种原因,这段代码对于该词的任何含义都不好。根据C标准,它只是正确的。
答案 4 :(得分:0)
没有错。 更好的风格将是
const char *foo(int x);
然后你不能在没有丢弃const的情况下进入它。如果你真的想打破它,没有什么可以阻止你。
如果你想让它重新进入。
const char *foo(int x)
{
return (x? "not zero" : "zero");
}