zoukankan      html  css  js  c++  java
  • 一个由sizeof引出的有意思的问题

      前段时间在一个论坛上看到了一个帖子,lz发了一个代码,如下。注意,sizeof语句后面没有加分号。

      

    #include <stdio.h>

    int main()
    {
    int a;
    a
    = sizeof(long double)
    printf(
    "%d\n",a);
    return 0;
    }

      这个代码实在太简单了,我想大家学C/C++时都使用过这个代码,我们都会这样去看各种基本数据类型占用了几个字节的存储空间,但是这个敲错的代码却出现了一个很诡异的问题:尽管sizeof一句后面忘了加分号,但是使用VC6编译这个代码却是零错误零警告,只是运行时没有任何输出,这是怎么回事呢?

      我花了一个多小时的时间,脑袋才终于转过弯来。首先我们要明确一点,尽管我们通常都是用sizeof(a)这种形式使用它,但是sizeof是操作符,不是函数,也就是说sizeof a这种调用是完全正确的,就像++、--以及new这些操作符一样,括号不是必须的,而且C语言对空格之类的字符并没有什么太严格的限制,所以"sizeof(long double)"和"printf("%d\n",a);"这两句被VC6编译器认为是同一句,相当于sizeof(long double)printf("%d\n",a);这一句的意思已经很明显了,是先对printf()函数的返回值进行强制类型转换,称为long double类型,然后将long double类型所占的字节数赋值给变量a。

      所以printf()函数是不会被执行的,我们只是需要对它的返回类型进行一次转换而已,它的返回类型是int,从stdio.h里的函数原型就能知道,没必要调用它!如果我们在printf()函数下面再加一句同样的printf语句,就可以看到这次成功地输出了a的值是8。

      从上面的分析来看,VC6能成功地编译这个程序是正确的,虽然不小心漏掉了一个分号,但是依旧是符合C语言规定的,但是如果到gcc或者VS2005下编译一下就发现,居然报错了!这又是为什么呢?

      看一下VS2005的报错信息吧,"error C2146: syntax error : missing ';' before identifier 'printf'",这个报错信息很准确,我们确实是漏掉了一个分号,但是漏掉了也符合上面的分析啊,怎么会被发现了呢?我感觉这种错误应该是lint之类的东西才能发现的,就像if(i = 1)之类的错误一样,不过既然编译器这么报错,我们就去翻一下C99标准吧,在6.5.3 Unary Operators的一开始Syntax小节就能看到下面这个信息:

      unary operators

      从上图可以明显的看到sizeof后面跟数据类型的时候得有括号才行,如果是变量的话可以是没有括号的形式(为了兼容,用于变量名时加上括号也是可以的),所以VS2005就报错了,因为我们最上面给出的程序相当于是"sizeof long double;",这样显然就不对了,那么就是说其实错的还是VC6,可能开发VC6时并没有注意到这一点微妙的差别导致了这个问题,那么如果确实想在VS2005下这么使用该怎么办呢?那就是写成这种形式,"sizeof((long double)printf("%d\n",a));"这样就可以获得和VC6相同的结果了。

      为了证实确实是对printf()进行了强制类型转换我们可以写下面这个小程序来验证一下。

      

    #include <stdio.h>

    void foo(int a)
    {
    printf(
    "Hello,world!\n");
    }

    int main()
    {
    int a;
    a
    = sizeof(long double)
    foo(a);
    return 0;
    }

      只是把printf()函数改成了foo()函数,但是这次VC6编译时就报错了,报错信息是"error C2069: cast of 'void' term to non-'void'",看,我们的foo()函数返回的是void类型,也就是说根本没返回什么,再进行强制类型转换就会报错了,我们也就可以确定使用printf()函数时不报错就是因为成功地进行了转换。

      总结一下,我们可以知道使用sizeof操作符时,如果后面是变量名,那么可以是sizeof a也可以是sizeof(a),但是如果后面是数据类型时,那么就只能是sizeof(int)而不能是sizeof int。VC6编译器就是因为对此的检查不够严格导致了这个微妙的小错误。

  • 相关阅读:
    寒假学习笔记12
    寒假学习笔记11
    寒假学习笔记10
    寒假学习笔记09
    JSoup简单测试
    App开发环境_Eclipse_20160927
    App开发环境_Eclipse_20160925
    ZC_源码编译真机烧写_20160424
    ZC_源码编译真机烧写_20160423
    sdk下载
  • 原文地址:https://www.cnblogs.com/pianoid/p/2073911.html
Copyright © 2011-2022 走看看