在C中编辑不可变字符串与旧的编译器一起工作,但与现代编译器不同



我正在处理一些在Solaris 10上运行的古老遗留代码。在旧服务器上,代码编译和运行都没有遇到问题。

然后,代码被迁移到Solaris11服务器,代码仍然在那里编译,但当它运行时,它会创建一个seg故障核心转储。

在这两种情况下,使用的编译器都是/opt/SUNWspro/bin/cc。

以下是代码片段:

#include <stdio.h>
char   *blank = "                                   ";
main(argc,argv)
int argc;
char **argv;
{
blank[35] = '';
printf("Success.n");
}

这在Solaris 10上起作用,但在Solaris 11上会导致分段故障(核心转储(。通常情况下,我会说segfault是由于试图在blank[]数组只上升到blank[34](它用35个空格字符初始化(时写入blank[35]而引起的,但这段代码在Solaris 10上工作。

此外,当我将行更改为'blank[34]='\0';'时在新服务器上,我仍然得到一个segfault核心转储。

当我将空白更改为普通数组(并使main现代化(时,一切都很好,正如我所期望的那样:

#include <stdio.h>
char blank[35];
int main(int argc,char **argv)
{
int i;
for (i=0; i<34; i++)
{
blank[i] = ' ';
}
blank[34] = '';
printf("Success.n");
return 0;
}

我真正需要知道的是,为什么这些代码在旧服务器上运行良好,我忽略了什么?我可以更改代码以使用普通数组使其在新服务器上运行,但这可能会导致什么样的问题?

他们是否使用完全相同版本的C编译器和完全相同的标志?

旧版本的Studio编译器(/opt/SUNWspro/…(默认情况下会将常量字符串放在可写内存中,除非您使用-features=conststrings标志将它们放在只读内存中。

Studio编译器的后续版本将-features=conststrings设为默认值,并要求-features=no%conststrings使其再次可写,如Studio 12.6文档中所示https://docs.oracle.com/cd/E77782_01/html/E77788/bjapr.html#OSSCGbjaqo.

这类似于gcc对等效标志-fwritable-strings所做的操作,该标志在最旧版本中默认为打开,然后在中默认为关闭在gcc 4.0中删除之前的几个版本中,始终使用常量字符串在只读存储器中。

请注意,您没有char blank[],而是指向String Literal的char *blank。字符串文字是不可变的。此代码试图修改blank所指向的文字中的一个字符,从而导致"未定义的行为"。Undefined Behavior的有趣之处在于它可以做任何事情,包括按照你想要的方式发挥作用

同样值得注意的是,字符串文字已经隐式地以null结尾,因此无论怎样,在末尾显式添加"\0"都是不必要的。

很可能,问题不在于操作系统版本,而在于构建代码的编译器。这段代码有很多问题,很容易看出它是如何在一个编译器上工作的,而在另一个编译器中则不然。假设我们不知道您使用的是什么编译器,我就不做推测了。

但我敢打赌,如果这两台机器有相同的硬件体系结构(例如,两个都是superparc(,如果你在Solaris 10上编译二进制文件,它在Solaris 11上运行得很好。

最新更新