C语言中数组名是常量,存在哪了?

suxiuapple 2011-04-24 03:50:52
C语言中数组名是常量,存在哪了?
int a[5];
a 存在哪了?
...全文
1215 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
nobody@noone 2011-04-25
  • 打赏
  • 举报
回复
数组名不是常量, a[5] 和 jdirewhuifhuiewt[5] 在编译阶段没什么不一样
pamtry 2011-04-25
  • 打赏
  • 举报
回复
关于常量概念,我的说法的确很不谨慎,希望这点不要误导到旁人

因为是数学出身,对于类似常量这种概念,很容易被数学上的惯性影响到,这种不严谨的地方多谢指正,以后我会多多注意。

另外对于抽象和实现的问题,我个人的观点是这样的。
实现是为了完成抽象的要求所做的底层工作,因此抽象确实是实现的唯一标准,从抽象入手并且加以理解确实是学习C/C++的正途。
但是另外一个方面,脱离了实现去学习C/C++也绝对是不完整的。作为最接近硬件的高级语言(虽然是不是真正的高级语言这点似乎也有些争议),为什么要用C来写系统写驱动?为什么要用C++来做游戏做SERVER做数据库?脱离了对底层的良好控制力这个最大的优势,C/C++和JAVA/.NET的竞争还能有多少优势呢?

C/C++虽然号称有着良好的可移植性,但是同一段代码在不同平台下的不同实现方式,往往会产生质的差别。作为C/C++的使用者,如果不去了解自己所使用平台下关键代码的实现方式,想写出优秀的C代码真的有可能么?

当然,以上是个人观点,欢迎讨论

[Quote=引用 16 楼 supermegaboy 的回复:]

引用 14 楼 pamtry 的回复:
所为的常量也只是为了方便理解,确切的说,C中数组名的实现更类似于预编译的#define

当然,这只是数组名在数值上的特性,至于说类型、大小、取地址等操作所呈现出的数组特性,说明C在数组上做的文章远不是一个数组地址那么简单的事情

但是,LZ在这个帖子中的问题是“数组名存储在内存中的哪里”,这显然不是一个单纯从C语法角度就能说清楚的事情。标准是底……
[/Quote]
飞天御剑流 2011-04-25
  • 打赏
  • 举报
回复
实现是为了完成抽象的要求所做的底层工作,因此抽象确实是实现的唯一标准,从抽象入手并且加以理解确实是学习C/C++的正途。但是另外一个方面,脱离了实现去学习C/C++也绝对是不完整的。
---------------------------------------------------------------------
对的。增强对实现机制的了解,是优秀程序员的必修素质,只要注意从一个正确的方向去理解高层语义就行了。



作为最接近硬件的高级语言(虽然是不是真正的高级语言这点似乎也有些争议),为什么要用C来写系统写驱动?为什么要用C++来做游戏做SERVER做数据库?脱离了对底层的良好控制力这个最大的优势,C/C++和JAVA/.NET的竞争还能有多少优势呢?
---------------------------------------------------------------------------
C/C++是高级语言这一点是毫无疑问的,这一点并不能因为他们能提供访问硬件的语言设施而产生怀疑。有一点你可能会感到诧异,从语言历史分类上来说,汇编是世界上第一种高级语言!只不过抽象的程度比较低而已。




C/C++虽然号称有着良好的可移植性,但是同一段代码在不同平台下的不同实现方式,往往会产生质的差别。作为C/C++的使用者,如果不去了解自己所使用平台下关键代码的实现方式,想写出优秀的C代码真的有可能么?
----------------------------------------------------------------------------------
是的,就像第一点那样,对实现方式的了解是必须的,只要保持头脑清醒。



赵4老师 2011-04-25
  • 打赏
  • 举报
回复
《编译原理》
《程序员的自我修养——链接、装载与库》

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
svtanto 2011-04-24
  • 打赏
  • 举报
回复
你被数组名是常量这句话给迷惑了,不是数组名是常量,正确的描述应该是数组名是只读的。和你程序中定义的常量不要混为一谈。
download800 2011-04-24
  • 打赏
  • 举报
回复
LZ问的是a存在哪了, 不是a所指向的具有5个int型整数的数组(它当然存在在栈中了), a被编译器分配到了可执行文件的符号表中了, 字符串a会映射到一个指针, 这个指针就是数组的首地址.C语言中的每个变量名都会分配到符号表中的.
飞天御剑流 2011-04-24
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 pamtry 的回复:]
所为的常量也只是为了方便理解,确切的说,C中数组名的实现更类似于预编译的#define

当然,这只是数组名在数值上的特性,至于说类型、大小、取地址等操作所呈现出的数组特性,说明C在数组上做的文章远不是一个数组地址那么简单的事情

但是,LZ在这个帖子中的问题是“数组名存储在内存中的哪里”,这显然不是一个单纯从C语法角度就能说清楚的事情。标准是底线,但是如果标准能解决一切,答疑解惑就没有意……
[/Quote]

我所说的关于标准的阅读,并非指数组名的内存映像,指的是常量这个概念,请重新看看我11楼的原话。

从你在3楼的话“a是一个常量,哪里都没有存”来说,其实你是把不变的量理解成就是常量,C中的常量观念远非如此,所以我建议你阅读一下标准。

至于数组名的内存映像,很多编译环境实现为代码段中的立即数,这是因为这些编译环境认为在这种情况下立即数实现是最合理的,但是别把合理性理解成了必然性,换一个环境,合理性就可能有所不同。抽象是唯一的,但实现不是唯一的。

C/C++是高级语言,象数组、指针等等这些东西都是高层抽象语义,在实现的过程中,这些高层抽象语义被剥离,高层语义已经不再存在,再也没有C/C++了,因此从这个方向上是无法理解一个真实的C/C++的。
pathuang68 2011-04-24
  • 打赏
  • 举报
回复
pamtry 2011-04-24
  • 打赏
  • 举报
回复
所为的常量也只是为了方便理解,确切的说,C中数组名的实现更类似于预编译的#define

当然,这只是数组名在数值上的特性,至于说类型、大小、取地址等操作所呈现出的数组特性,说明C在数组上做的文章远不是一个数组地址那么简单的事情

但是,LZ在这个帖子中的问题是“数组名存储在内存中的哪里”,这显然不是一个单纯从C语法角度就能说清楚的事情。标准是底线,但是如果标准能解决一切,答疑解惑就没有意义了不是

从实现的角度来理解C/C++,是不是一个错误的方向,我觉得有待商议。有喜欢从底层看问题的人,也有习惯于从表层看问题的人,这是不是一个需要去下一个对错定义的事情呢。我只能呵呵了

[Quote=引用 11 楼 supermegaboy 的回复:]

引用 8 楼 pamtry 的回复:
如果提到局部数组和全局(static)数组的区别的话,当然是有所不同,不过最终也是殊途同归

对于全局(static)数组来说,数组名就是一个彻头彻尾的常量
而对于局部数组来说,数组名是一个固定的栈内偏移量(以call之后的栈顶为标志)

但是,两者都有一个决定性的共同点,那就是不论是单纯的常量还是栈内偏移,这个数值都是只出现在代码段中可执行机器……
[/Quote]
飞天御剑流 2011-04-24
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 pamtry 的回复:]
不过,单纯的讨论数组名的存储位置是没有意义

1、数组名在没有任何外部调用(单纯只是定义数组)的情况下,是不会在内存中显式出现的

2、即使是被调用,只能做为左值的数组名,也只是出现在机器码中的操作数位置,不论全局还是局部数组

3、一般只有通过lea/mov/push等操作后,做为操作数的数组名,才真正的进入栈内参与运算,不过此时的数组名也只能算作是原本数组名的副本了吧
[/Quote]

先搞清楚啥是抽象,啥是实现。
pamtry 2011-04-24
  • 打赏
  • 举报
回复
不过,单纯的讨论数组名的存储位置是没有意义

1、数组名在没有任何外部调用(单纯只是定义数组)的情况下,是不会在内存中显式出现的

2、即使是被调用,只能做为左值的数组名,也只是出现在机器码中的操作数位置,不论全局还是局部数组

3、一般只有通过lea/mov/push等操作后,做为操作数的数组名,才真正的进入栈内参与运算,不过此时的数组名也只能算作是原本数组名的副本了吧
飞天御剑流 2011-04-24
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 pamtry 的回复:]
如果提到局部数组和全局(static)数组的区别的话,当然是有所不同,不过最终也是殊途同归

对于全局(static)数组来说,数组名就是一个彻头彻尾的常量
而对于局部数组来说,数组名是一个固定的栈内偏移量(以call之后的栈顶为标志)

但是,两者都有一个决定性的共同点,那就是不论是单纯的常量还是栈内偏移,这个数值都是只出现在代码段中可执行机器码中。而不像其它局部或者全局变量一样,会出……
[/Quote]

请详细阅读一下c标准,学习一下什么是常量,什么是常量表达式。

另:从实现的角度来理解C/C++,是一个错误方向。
漫步者、 2011-04-24
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 kid_coder 的回复:]
C/C++ code

int a[5]; //存在数据段
const int a[5]; //存在代码段
fun()
{
int c[5]; //存在栈段
}
int main()
{
int b[5]; //存在栈段
return 0;
}
[/Quote]

//分析有点错误
pamtry 2011-04-24
  • 打赏
  • 举报
回复
这么讲吧,任何数组的数组名,都是只存在于代码段当中的某个数值,这个数值有可能是直接寻址的一个地址,也有可能是间接寻址中的一个偏移量

这也变相的在原理上说明了为什么不能对数组名进行赋值,因为代码段为只读属性(当然从语法的角度来说,不允许赋值有着其它方面的缘故)
pamtry 2011-04-24
  • 打赏
  • 举报
回复
如果提到局部数组和全局(static)数组的区别的话,当然是有所不同,不过最终也是殊途同归

对于全局(static)数组来说,数组名就是一个彻头彻尾的常量
而对于局部数组来说,数组名是一个固定的栈内偏移量(以call之后的栈顶为标志)

但是,两者都有一个决定性的共同点,那就是不论是单纯的常量还是栈内偏移,这个数值都是只出现在代码段中可执行机器码中。而不像其它局部或者全局变量一样,会出现在代码段外例如堆栈或者静态存储区中。

[Quote=引用 6 楼 supermegaboy 的回复:]

引用楼主 suxiuapple 的回复:
C语言中数组名是常量,存在哪了?
int a[5];
a 存在哪了?


找个c90的编译器,编译一下如下代码,如果你用gcc,要注意加上-pedantic和-error移除GNU扩展并执行严格的标准c错误信息。

C/C++ code

int main( void )
{
static int a[10], b[10];
……
[/Quote]
qinghu120 2011-04-24
  • 打赏
  • 举报
回复
数组名是一个指针常量, 这个数组名 函数是属于 局部变量,所以存储在 栈区域
飞天御剑流 2011-04-24
  • 打赏
  • 举报
回复
[Quote=引用楼主 suxiuapple 的回复:]
C语言中数组名是常量,存在哪了?
int a[5];
a 存在哪了?
[/Quote]

找个c90的编译器,编译一下如下代码,如果你用gcc,要注意加上-pedantic和-error移除GNU扩展并执行严格的标准c错误信息。


int main( void )
{
static int a[10], b[10];
int c[10], d[10];
int* e[] = { a, b };
int* f[] = { c, d };
return 0;
}


编译完后好好想想为什么,找到答案后再好好重新想想数组名是常量吗???
hzc543806053 2011-04-24
  • 打赏
  • 举报
回复
内存当中
书虫 2011-04-24
  • 打赏
  • 举报
回复
符号表段里记载着符号a到其指向地址的映射
a数组的值则存在数据段中(前提a数组是全局或静态)。
pamtry 2011-04-24
  • 打赏
  • 举报
回复
a是一个常量,哪里都没有存

可以类似等同于

#define a 0x004AFF2B  //实际的数值是在编译的时候由编译器计算生成的
加载更多回复(2)

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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