在C中取消引用指向超出范围的静态数据的指针

时间:2012-04-03 18:05:04

标签: c pointers scope undefined-behavior

免责声明:这个问题严格来说是学术性的。我即将给出的例子可能是糟糕的风格。

假设在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的输出。但同样,这实际上是由标准定义的吗?

5 个答案:

答案 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");
}