zoukankan      html  css  js  c++  java
  • C语言中不同数据类型在内存中的存储格式研究

      学了这么多年C语言、C++、VC、MFC,但却从来没有认真研究过各种数据类型在内存中是如何存储的。感觉自己一直在弄的都是皮毛,没有触及真正核心的东西。直到昨天,重新翻看谭浩强老师经典的《C程序设计(第三版)》,在“第十四章 常见错误和程序调试”中有一个例子是这样的:

    1     int a=3;
    2     float b=4.5;
    3     printf("%f %d",a,b);

      输出的结果是这样的:

      为什么会是这样的结果呢?让我们看一看a和b在内存中的存储方式吧?

      int 和 long 一样,按 2 的补码、低位字节在前的形式存储于 4 个字节中;

      float 按 IEEE 754 单精度数的形式存储于 4 个字节中;

      double 按 IEEE 754 双精度数的形式存储于 8 个字节中。

      a是int型的,在内存中占4个字节,在内存中的存储方式:

      地址:0x0012ff7c  0x0012ff7d  0x0012ff7e  0x0012ff7f

      数值:  03      00       00       00

      b是float型的,在内存中占4个字节,在内存中的存储方式:

      地址:0x0012ff70  0x0012ff71  0x0012ff72  0x0012ff73

      数值:  00      00       90       40

      看了printf的源码:

    1 int printf( char * format , ...)
    2 {
    3     va_list ap;
    4     int n;
    5     va_start (ap,format);
    6     n=vprintf(format ,ap);
    7     va_end(ap);
    8     return n;
    9 }

      又看了vprintf的源码:

      1 /***
      2 *vprintf.c - printf from a var args pointer
      3 *
      4 *       Copyright (c) Microsoft Corporation. All rights reserved.
      5 *
      6 *Purpose:
      7 *       defines vprintf() - print formatted data from an argument list pointer
      8 *
      9 *******************************************************************************/
     10 
     11 #include <cruntime.h>
     12 #include <stdio.h>
     13 #include <dbgint.h>
     14 #include <stdarg.h>
     15 #include <internal.h>
     16 #include <file2.h>
     17 #include <mtdll.h>
     18 #include <stddef.h>
     19 
     20 /***
     21 *int vprintf(format, ap) - print formatted data from an argument list pointer
     22 *
     23 *Purpose:
     24 *       Prints formatted data items to stdout.  Uses a pointer to a
     25 *       variable length list of arguments instead of an argument list.
     26 *
     27 *Entry:
     28 *       char *format - format string, describes data format to write
     29 *       va_list ap - pointer to variable length arg list
     30 *
     31 *Exit:
     32 *       returns number of characters written
     33 *
     34 *Exceptions:
     35 *
     36 *******************************************************************************/
     37 
     38 int __cdecl vprintf_helper (
     39         OUTPUTFN outfn,
     40         const char *format,
     41         _locale_t plocinfo,
     42         va_list ap
     43         )
     44 /*
     45  * stdout 'V'ariable, 'PRINT', 'F'ormatted
     46  */
     47 {
     48         REG1 FILE *stream = stdout;
     49         REG2 int buffing;
     50         REG3 int retval;
     51 
     52         _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
     53 
     54 
     55         _lock_str(stream);
     56         __try {
     57 
     58         buffing = _stbuf(stream);
     59         retval = outfn(stream, format, plocinfo, ap );
     60         _ftbuf(buffing, stream);
     61 
     62         }
     63         __finally {
     64             _unlock_str(stream);
     65         }
     66 
     67         return(retval);
     68 }
     69 
     70 int __cdecl _vprintf_l (
     71         const char *format,
     72         _locale_t plocinfo,
     73         va_list ap
     74         )
     75 {
     76     return vprintf_helper(_output_l,format, plocinfo, ap);
     77 }
     78 
     79 int __cdecl _vprintf_s_l (
     80         const char *format,
     81         _locale_t plocinfo,
     82         va_list ap
     83         )
     84 {
     85     return vprintf_helper(_output_s_l,format, plocinfo, ap);
     86 }
     87 
     88 int __cdecl _vprintf_p_l (
     89         const char *format,
     90         _locale_t plocinfo,
     91         va_list ap
     92         )
     93 {
     94     return vprintf_helper(_output_p_l,format, plocinfo, ap);
     95 }
     96 
     97 int __cdecl vprintf (
     98         const char *format,
     99         va_list ap
    100         )
    101 {
    102     return vprintf_helper(_output_l,format, NULL, ap);
    103 }
    104 
    105 int __cdecl vprintf_s (
    106         const char *format,
    107         va_list ap
    108         )
    109 {
    110     return vprintf_helper(_output_s_l,format, NULL, ap);
    111 }
    112 
    113 int __cdecl _vprintf_p (
    114         const char *format,
    115         va_list ap
    116         )
    117 {
    118     return vprintf_helper(_output_p_l,format, NULL, ap);
    119 }

      发现里面使用了可变参数,即函数根本不知道传进来的参数类型,所以可能出现匹配错误的问题。4.5如果按照double类型存储格式是:

      0x4012000000000000,按照%d格式输出就是1074921472,与我们前面得到的结果正好相同。

      下面,再做一个实验:

    1     int a=3;
    2     int *p=&a;
    3     double b=4.5;
    4     double *q=&b;
    5     printf("%f %d",a,b);

      运行结果如下:

      与前面得到的结果完全相同。

      看来问题的原因在于可变参数类别表,传入的参数类型与编译器的解释类型不一致引起的,所以以后编程时一定要慎用可变参数列表。在网上看到一篇文章也提到了使用可变参数列表应该注意的问题:

      (1)可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不同参数的个数和类型;

     

      (2)如果我们不需要一一详解每个参数,只需要将可变列表拷贝至某个缓冲,可用vsprintf函数;

     

      (3)因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码;

  • 相关阅读:
    ionic localstorage
    angular 中文鏈接
    把jqmobi 變成jQuery 的插件 從此使用jQuery
    jqmobi 的一些設置
    ionic ngcordova map 地圖
    ionic pull to refresh 下拉更新頁面
    json 對象的序列化
    鍵盤彈出,頁面佈局被推上去了.....
    Cordova V3.0.0中config.xml配置文件的iOS Configuration
    android ios 只能輸入數字 不能輸入小數點的 函數 cordova
  • 原文地址:https://www.cnblogs.com/onedime/p/2779707.html
Copyright © 2011-2022 走看看