问一个难一点的关于全局变量extern的问题

threeleafzerg007 2008-12-30 06:46:04
在 main.cpp 声明全局变量 char g_char_array[] = "hello!World\n"

在 某一头文件 a.h 声明 void print_global();

在 a.cpp 声明 extern char *g_char_array; 同时
void print_global()
{
printf("%s",g_char_array);
}

在 main.cpp 里

printf("%s",g_char_array);
print_global;


编译无问题,运行报错,segmentation fault,若a.cpp 中 改成 extern char g_char_array[]; 一切正常了。

1.为何编译不报错?(当然g_char_array确实是一个char *指针类型)
2.我打印出过错误的g_char_array的地址,发现 它将 main.cpp g_char_array字符串内容的前四个字节 copy 给了自己,这是为什么?

希望能从编译器的角度(编译,链接),以及汇编的角度来解释这个问题。 (貌似是EMC的面试题)

...全文
249 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
asksgp 2008-12-30
  • 打赏
  • 举报
回复
噢,明白了!
g++ -Wall a.h a.cpp main.cpp -o main.out

抄别人一段话
extern的使用:
.h 文件中extern int n 就是要告诉包含该头文件的 .cpp 文件,这个变量n是在外面定义的。在所有包含这个 .h 文件的 .cpp 文件中,这个变量n只能出现一次定义int n。这个变量在任何一个文件中被改变,所有的文件中的函数都会看到它的变化。
asksgp 2008-12-30
  • 打赏
  • 举报
回复
例如a.cpp,main.cpp 怎么编译运行?
asksgp 2008-12-30
  • 打赏
  • 举报
回复
哪位能结合a.cpp,main.cpp, a.h讲讲extern 变量 在这里的用法,看了网上说的不是很明白,谢谢!
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 Chiyer 的回复:]
数组名是一个地址,而不是一个指针

你的原始类型是数组


char g_char_array[] = "hello!World\n"

符号g_char_array就对应这个数组地址,在这里也就是字符串"hello!World\n" 的首地址

比如假设是 0x00407000 "hello world"


而你重声明的类型是指针

extern char *g_char_array

这里符号 g_char_array对应的是指针变量g_char_array的地址

所以当连接的时候,连接器把0x00407000 "hello world" 和…
[/Quote]
顶,星羽讲的极是
帅得不敢出门 2008-12-30
  • 打赏
  • 举报
回复
问题:extern 变量

  在一个源文件里定义了一个数组:char a[6];
  在另外一个文件里用下列语句进行了声明:extern char *a;
  请问,这样可以吗?


  答案与分析:
  1)、不可以,程序运行时会告诉你非法访问。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。应该将声明改为extern char a[ ]。

  2)、例子分析如下,如果a[] = "abcd",则外部变量a=0x61626364 (abcd的ASCII码值),*a显然没有意义

  显然a指向的空间(0x61626364)没有意义,易出现非法内存访问。

  3)、这提示我们,在使用extern时候要严格对应声明时的格式,在实际编程中,这样的错误屡见不鲜。

  4)、extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在*.h中并用extern来声明。

threeleafzerg007 2008-12-30
  • 打赏
  • 举报
回复
8楼的解释不错 明天接分,12楼也有分
chenzhiyubuaa 2008-12-30
  • 打赏
  • 举报
回复
数组名和指针的区别,
数组名就是地址,实际上等于数组第一个元素的地址,
而指针是有存储空间的,指针的内容指向了另外一个地址。
printf("%s", g_char_array)会把g_char_array当成指针来用,因为声明的是char*类型


比如,g_char_array = 0x0,如果当成数组名来使用,会直接把这个值传给printf,
如果把g_char_array当成指针来使用,那么会把0x00,0x01,0x02,0x03的地址看成是指针,
而其内容就是lz提到的前四个字符是指针指向的地址

如果要从汇编上说的话,大概会是这样

如果声明为extern char g_char_array[]; 那么大概会有一个_g_char_array的全局变量,还会有类似
mov eax, _g_char_array
push eax
这样的动作

如果申明为extern char* g_char_array;差不多会是这样
mov eax, [0x0];g_char_array的值为 0x0
push eax

所以在extern的时候是啥就写啥
agaric 2008-12-30
  • 打赏
  • 举报
回复
本来就是两回事哦
herman~~ 2008-12-30
  • 打赏
  • 举报
回复
MARK
funnybunny 2008-12-30
  • 打赏
  • 举报
回复
学习~
星羽 2008-12-30
  • 打赏
  • 举报
回复
数组名是一个地址,而不是一个指针

你的原始类型是数组


char g_char_array[] = "hello!World\n"

符号g_char_array就对应这个数组地址,在这里也就是字符串"hello!World\n" 的首地址

比如假设是 0x00407000 "hello world"


而你重声明的类型是指针

extern char *g_char_array

这里符号 g_char_array对应的是指针变量g_char_array的地址

所以当连接的时候,连接器把0x00407000 "hello world" 和 符号g_char_array重新关联

效果相当于 &g_char_array = 0x00407000 "hello world";

所以g_char_array的值就变成了0x00407000 "hello world";的内容,由于是指针,所以就是前4个字节 "hell" 对应16进制0x6c6c6568

而0x6c6c6568 表示的是字符串 "hell" 而不是一个有效的指针变量,所以出错
ReViSion 2008-12-30
  • 打赏
  • 举报
回复
学习
「已注销」 2008-12-30
  • 打赏
  • 举报
回复
学习
speeder53 2008-12-30
  • 打赏
  • 举报
回复
mk
机智的呆呆 2008-12-30
  • 打赏
  • 举报
回复
只有在作为函数参数时,数组退化成指针~~~

#include<iostream>
using namespace std;
void test1(char a[])
{
cout<<typeid(a).name()<<endl;
}
void test2(char *a)
{
cout<<typeid(a).name()<<endl;
}
char *p1="a";
char p2[]="a";

int main()
{
test1(p2);
test2(p2);
cout<<typeid(p1).name()<<endl;
cout<<typeid(p2).name()<<endl;
system("pause");
}
xiaoyisnail 2008-12-30
  • 打赏
  • 举报
回复
关键是误把char*和char[]当成同样的类型了,记住数组只是在用作参数传递是才退化成相应的指针类型
xiaoyisnail 2008-12-30
  • 打赏
  • 举报
回复
[Quote=引用楼主 threeleafzerg007 的帖子:]
在 main.cpp 声明全局变量 char g_char_array[] = "hello!World\n"

在 某一头文件 a.h 声明  void print_global();

在 a.cpp  声明 extern char *g_char_array; 同时
void print_global()
{
    printf("%s",g_char_array);
}

在 main.cpp 里   

printf("%s",g_char_array);
print_global;


编译无问题,运行报错,segmentation fault,若a.cpp 中 改成 extern char g_char_array[]; 一切正常了。

1.为何编译不…
[/Quote]

char *g_char_array和char g_char_array[]不是一个东西啊,所以在a.cpp里没有用到main.cpp里的那个全局数组,编译时因为有extern声明,所以编译器能认识g_char_array这个符号,而且在编译a.pp时认为这是一个char*,但是运行时因为char* g_char_array没有初始化过,必然运行时出错啊
就呆在云上 2008-12-30
  • 打赏
  • 举报
回复

你理解错了
你的maincpp里面定义的是什么?
是:char g_char_array[] = "hello!World\n"

那你的a.cpp里面定义的是什么?
extern char *g_char_array;
上面的是数组
下面的是指针,两个不是一个东西,你下面的属于貌似extern了却属于重新定义的全局指针,重新定义一个指针却没有指向,然后你用:
printf("%s",g_char_array);
打印一个没有初始化的字符串,会不报错?

这样:

//main.cpp
#include "h.h"
char *g_char_array = "hello!World\n";
int main() {
printf("%s",g_char_array);
print_global();
}

//a.cpp
#include "h.h"
extern char *g_char_array;
void print_global()
{
printf("%s",g_char_array);
}

//a.h

#include <stdio.h>

void print_global();

或者:

//main.cpp
#include "h.h"
char g_char_array[] = "hello!World\n";
int main() {
printf("%s",g_char_array);
print_global();
}

//a.cpp
#include "h.h"
extern char g_char_array[];
void print_global()
{
printf("%s",g_char_array);
}

//a.h

#include <stdio.h>

void print_global();


要么都用指针,要么都用数组,指针和数组不要说了吧

64,682

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧