免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 6719 | 回复: 20
打印 上一主题 下一主题

看到C版上有人问的一个问题想到的,关于数组和指针 [复制链接]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-29 18:35 |只看该作者 |倒序浏览
我用如下代码测试
/*1.c*/
#include <stdio.h>
char s[]="test\n";
void func()
{
        printf(s);
}
/2.c*/
#include <stdio.h>
#include <stdio.h>
extern char*s;
void func(void);
int main()
{
        func();
        printf(s);
        return 0;
}

编译链接再执行一下:
[root@SRUCAU tmp]# gcc -c 1.c && gcc -c 2.c && gcc 1.o 2.o -o a.out
[root@SRUCAU tmp]# ./a.out
test
Segmentation fault

呵呵,原因是什么呢?
如果是C版,可能这个帖子可能有点吹毛求疵,不过在这个版么,那就不算了.

论坛徽章:
0
2 [报告]
发表于 2009-12-29 21:37 |只看该作者
原因在于 1.c 和 2.c  中 s 的类型是不一样的。在 1.c 中, s 是字符串"test\n"的起始地址。 func 调用 printf 时传递的是 s 本身的地址。 在 2.c 中,s 是一个字符指针变量。main 调用 printf 时传递的是 s 变量的值,这个值就是把 "test\n" 这个字符串以及后面的若干个字节组成的一个整数。当 printf 把这个整数当成字符串的地址去访问时,一般就会seg fault。

论坛徽章:
0
3 [报告]
发表于 2009-12-29 22:02 |只看该作者
拿这种事情吹毛求疵相当无聊,你用C思考,有人用ASM思考,我用IR思考不行么?
中国人学英语,语法特棒,交流就shit了。美国人语法特明白?那是语感,本能的反应,写代码写到背语法,简直就是杯具!

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
4 [报告]
发表于 2009-12-30 14:16 |只看该作者
其实我想问的问题一共有四个:
第一,为什么可以链接通过.
第二,为什么链接的时候连个warning都没有.
第三,为什么第一个test可以打出来.
第四,为什么第二个就崩了.

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
5 [报告]
发表于 2009-12-30 14:18 |只看该作者
再引申一个吧,你可以设想出一种编译(广义的,不分编译/汇编/链接过程)的途径让它这里产生一个错误吗?
也就是说,如果你是当初设计C语言编译器的那个人,呵呵

论坛徽章:
0
6 [报告]
发表于 2009-12-31 03:37 |只看该作者
C版的那个题目有点夸张. 如果从汇编看,我可以说"所有"的编程语言都没有数组. 因为最后都会变成汇编,而汇编里又没有数组.

关于LZ的问题,我觉得即使是设计C语言的人,他关注的也主要是语法. 在具体实现的时候难免有一些灰色地带,也就是没有明确规定的地方. 具体编译器怎么实现是不确定的.
比如MS VC 和GCC 里面某些同样的语句就可能产生不同的结果, 因为那条语句的含义本身就是模糊的,没在标准里定义的. 随便你编译器怎么弄.

论坛徽章:
0
7 [报告]
发表于 2010-01-13 01:26 |只看该作者
"退化现象 "
The implicit conversion from a function (or array) to a pointer is often called decay. ( c++ templates:the complete guide 22.2 Pointers and References to Functions)

http://www.lysator.liu.se/c/c-faq/c-2.html

论坛徽章:
0
8 [报告]
发表于 2010-01-13 17:27 |只看该作者
原帖由 cjaizss 于 2009-12-30 14:16 发表
其实我想问的问题一共有四个:
第一,为什么可以链接通过.
第二,为什么链接的时候连个warning都没有.
第三,为什么第一个test可以打出来.
第四,为什么第二个就崩了.



1)没有未解析的符号就可以链接过,
2)a.c 的s和b.c的s对链接器来说是一样的。它不管语法上被声明成了什么类型。
3)正常现象
4)楼上有人解释了打印的是0x74736574这个地址的东西

具体原因就是
当声明数组的时候
char s[] = "test";

表示s是一个地址,那么生成汇编的代码就是
_s:
        .ascii "test\0"

当声明成字符串的时候:
char *s = "test";
表示s是一个指针,它的值是常量"test"的地址。
生成的汇编是:
LC0:
        .ascii "test\0"
        .data
        .align 4
_s:
        .long   LC0


当使用一个指针的时候,编译器会生成代码:先把s这个符号对应的地址指向的那个dword(假设是32bit系统)取出来,然后用这个值来取内容。
b.c实际就是欺骗编译器生成了错误的代码。导致b.o将test当成了地址

论坛徽章:
0
9 [报告]
发表于 2010-01-13 20:54 |只看该作者
原帖由 cjaizss 于 2009-12-30 14:16 发表
其实我想问的问题一共有四个:
第一,为什么可以链接通过.
第二,为什么链接的时候连个warning都没有.
第三,为什么第一个test可以打出来.
第四,为什么第二个就崩了.


后面的两个问题我前面已经回答过了。后面也有人举例说明了。

前面两个问题其实是一个问题。答案:链接器不做类型检查。

论坛徽章:
0
10 [报告]
发表于 2010-01-13 20:57 |只看该作者
原帖由 cjaizss 于 2009-12-30 14:18 发表
再引申一个吧,你可以设想出一种编译(广义的,不分编译/汇编/链接过程)的途径让它这里产生一个错误吗?
也就是说,如果你是当初设计C语言编译器的那个人,呵呵


可以把数据类型编码在符号名里,就像c++对函数名做的那样。但是这样的语言就不是现在的c语言了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP