繁体   English   中英

当实际和外部类型不同时会发生什么?

[英]What happens when actual and extern types are different?

我有两个文件:

AC

extern char *s;
int main()
{
    puts(s);
}

和bc:

char s[] = "hello";

我同时编译它们,没有错误。 但是程序在运行时崩溃了。 为什么? C语言规范的哪一部分说这是非法的?

您调用了未定义的行为 ,程序碰巧崩溃了。

N1256 6.2.7兼容型和复合型

1如果类型相同,则两种类型具有兼容类型。 用于确定两种类型是否兼容的附加规则在6.7.2中描述了类型说明符,在6.7.3中描述了类型限定符,在6.7.5中描述了声明符。 [...]

2涉及同一对象或功能的所有声明均应具有兼容类型; 否则,行为未定义。

在典型的环境中,当程序运行时,存储的内容将被读作指针,因为声明表明指针在ac ,但实际上是字符串的一部分(如果指针的大小是4个字节)并且它具有很少有机会成为有效的指针。 因此,从该地址读取很有可能导致分段错误。

如果你想真正了解 为什么崩溃(而不是为什么它不应该工作):

数组是内存中的一系列事物。 所以

char s[] = "hello";

这个变量的内存布局看起来像这样(假设它从0x00123400开始,带有4个字节的指针):

0x00123400:  'h'     <- address of s
0x00123401:  'e'
0x00123402:  'l'
0x00123403:  'l'
0x00123404:  'o'
0x00123405:  '\0'

要获取字符串的地址,它只使用固定的数字0x00123400。

指针保存其他内容的地址。 如果你有:

char *s = "hello";

然后编译器将数组“hello”放在某处,然后用其地址填充s:

0x00123400:  0x00     <- address of s
0x00123401:  0x56
0x00123402:  0x78
0x00123403:  0x9A

0x0056789A: 'h'      <- what s points to
0x0056789B: 'e'
0x0056789C: 'l'
0x0056789D: 'l'
0x0056789E: 'o'
0x0056789F: '\0'

要获取字符串的地址,它从固定数字0x00123400开始,并读取该位置的数字。

现在,如果你的变量实际上是一个char[]并且你告诉编译器它是一个char* ,那么它将把它当作指针。 这意味着它将从变量的地址开始,读取那里的数字,并使用该数字作为字符串的地址。

这个数字是多少? 好吧,我说过:

0x00123400:  'h'     <- address of s
0x00123401:  'e'
0x00123402:  'l'
0x00123403:  'l'

但那是谎言 - 我们都知道记忆只存储数字,而不是字母。 它只是简写,所以人们不必记住ASCII表。 真正存储的是:

0x00123400:  0x68     <- address of s
0x00123401:  0x65
0x00123402:  0x6C
0x00123403:  0x6C

因此,您的程序将读取0x68656C6C,然后它将尝试从地址0x68656C6C开始打印字符串,这很可能是无效的地址。

(注意:我在这个答案中忽略了字节顺序)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM