免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 西西弗西
打印 上一主题 下一主题

新鲜出炉的腾讯后台开发三面面试题! [复制链接]

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
1 [报告]
发表于 2011-09-29 13:50 |显示全部楼层
回复 139# x5miao

能完全正确编译linux内核的,基本上只有gcc,所以linux内核依赖的是gcc的实现,这个应该没什么问题。

offset是编译期常量,要么编译出错,要么就ok,不是吗?不会在运行期去实际解引用null指针的。

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
2 [报告]
发表于 2011-09-29 13:53 |显示全部楼层
本帖最后由 asuka2001 于 2011-09-29 13:55 编辑

我是指的是offset,不是offsetof。。。你使用宏获取这个编译期常量,只有两种可能。

我认为不可能编译器把编译期常量弄到运行期去获取,所以要么出错,要么就拿到offset了

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
3 [报告]
发表于 2011-09-29 13:59 |显示全部楼层
回复 143# x5miao

。。。我是说linux kernel是依赖于gcc的实现,因为基本能正确编译它的就是gcc,这个人家不存在问题。

至于维基百科中的担心,就本质而言,我们获取offset其实始终是依赖于编译器的,编译器如果对padding处理不同,你获取到的offset肯定不同,不是吗?

至于违反了C标准,我认为不太可能会出现严重后果。。。所以我们可以用这种方式来实现offsetof宏。

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
4 [报告]
发表于 2011-09-29 14:14 |显示全部楼层
回复 143# x5miao

我写了个测试程序,在没有打开gcc的任何优化的情况下,进行了编译,然后运行。没有出现段错误,应该可以说明即使不优化,至少gcc是把这个宏最后替换成了编译期的常量!

测试代码如下:
  1. #include "stdio.h"
  2. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

  3. struct test
  4. {
  5.         int a;
  6.         unsigned char b;
  7.         short c;
  8.         unsigned char d;
  9. };
  10. int main(void)
  11. {
  12.         printf("offset :%u\n", offsetof(test, c));
  13.         return 0;
  14. }
复制代码
结果如下:

test.jpg (11.39 KB, 下载次数: 31)

test.jpg

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
5 [报告]
发表于 2011-09-29 14:16 |显示全部楼层
回复 145# x5miao

那么有更好的可以在任何编译器上能获得正确结果的办法么?使用编译器的内部功能能算是c语言的实现么?

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
6 [报告]
发表于 2011-09-29 14:27 |显示全部楼层
这是个未定义行为,获取offset也本来就是个诡计,本身就是依赖于编译器的实现的!

我争论的并不是说它不是个未定义行为。。。我指的是,我们没有一个完美的解决办法,所以现在用这个宏来折中!

当然也许C99标准里可能对编译器有规定,要求所有的编译器实现内置功能获取offset。如果是这样的话,那么这个问题就完美解决了!我并不太清楚,如果有人知道的话可以指点一下,万分感谢!

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
7 [报告]
发表于 2011-09-29 14:50 |显示全部楼层
本帖最后由 asuka2001 于 2011-09-29 14:54 编辑

稍微有些好奇gcc的实际行为,以前只是认为直接offsetof就是把offset的编译常量返回了,所以反编译了程序看看
08048494 <main>:
8048494:       55                      push   %ebp
8048495:       89 e5                   mov    %esp,%ebp
8048497:       83 e4 f0                and    $0xfffffff0,%esp
804849a:       83 ec 10                sub    $0x10,%esp
804849d:       b8 00 00 00 00          mov    $0x0,%eax
80484a2:       83 c0 06                add    $0x6,%eax

80484a5:       89 44 24 04             mov    %eax,0x4(%esp)
80484a9:       c7 04 24 80 85 04 08    movl   $0x8048580,(%esp)
80484b0:       e8 0b ff ff ff          call   80483c0 <printf@plt>
80484b5:       b8 00 00 00 00          mov    $0x0,%eax
80484ba:       c9                      leave
80484bb:       c3                      ret   

从汇编上看,offset gcc是直接获得的6,然后把它和基址0相加。由于不需要解引用指针,所以没有引起段错误。。。
就这点上看,还真可以说offset虽然是编译常量,但是offsetof宏其实还是在运行期返回的值,所以我刚才的说法是错误的!
之所以没有出现段错误,仅仅是因为并不需要解引用null指针!

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
8 [报告]
发表于 2011-09-29 14:55 |显示全部楼层
如果是这样,那么offsetof宏的使用就真得有可能造成很严重的后果了。。。
不知道有没有实现的比较笨拙的编译器,会让offsetof宏来个段错误:)这个很好奇嘿嘿

论坛徽章:
17
水瓶座
日期:2013-08-29 12:09:27白羊座
日期:2014-08-07 12:36:42丑牛
日期:2014-07-24 12:44:41寅虎
日期:2014-04-16 16:15:33寅虎
日期:2014-03-12 09:28:43摩羯座
日期:2014-03-06 13:22:04技术图书徽章
日期:2014-03-06 11:34:50天蝎座
日期:2014-01-09 11:31:44寅虎
日期:2013-12-27 17:01:44双子座
日期:2013-12-27 12:32:29双子座
日期:2013-12-25 09:03:33丑牛
日期:2013-12-24 16:18:44
9 [报告]
发表于 2011-09-29 15:06 |显示全部楼层
回复 155# 狗蛋

感谢,看来offsetof的确属于诡计。。。还是只用编译器的实现吧!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP