我正在处理一些在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上运行得很好。