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编译器就是因为对此的检查不够严格导致了这个微妙的小错误。

  • 相关阅读:
    BZOJ5212 ZJOI2018历史(LCT)
    BZOJ5127 数据校验
    253. Meeting Rooms II
    311. Sparse Matrix Multiplication
    254. Factor Combinations
    250. Count Univalue Subtrees
    259. 3Sum Smaller
    156. Binary Tree Upside Down
    360. Sort Transformed Array
    348. Design Tic-Tac-Toe
  • 原文地址:https://www.cnblogs.com/pianoid/p/2073911.html
Copyright © 2011-2022 走看看