从printf说开去(四)

2024-01-03 01:18
文章标签 开去 printf

本文主要是介绍从printf说开去(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   (接上文)

 

   对于函数:

   float sumfunf(int num, …)
   {
         char* args = (char*)(&num)+sizeof(num);

         double result = 0;
         for(int n = 0; n < num; n++)
         {
              result += *(double*)(args + n*sizeof(double));
         }

         return (float)result;
   }
  
   第一个固定参数传入2,代表累加的数字个数为2,不定参数部分传入1和2作为参数,调用函数看看结果:
   float r = sumfunf(2, 1, 2),此时的r值也是不确定的。(如果用vc7以上做一个最简的控制台测试,大部分情况下r的值返回应该是0。)

   sumfunf函数在处理时,首先取得不定参数部分的偏移量,接下来按照“传入的参数都是double”这个假定进行处理。而sizeof(double)为8,也即是说,
   函数期望以8个字节为单位读取堆栈数据,此时的堆栈情况如下:

 

                                                                       栈顶
                                          ———————————————————————————————
                                             第一个参数num(用于表示不定参数个数),占用空间4字节。值为0×00000002
不定参数起始地址–>  ———————————————————————————————-
                                                0×00000001 (4字节)
                                                ————————–
                                                0×00000002 (4字节)
                                                ————————–
                                                …其他已经入栈的数据

 

        通过看上面这个堆栈示意,问题应该已经很明显了,sumfunf函数在取参数的时候是期望以double为单位获取数据的,机器并不知道这个数据是什么“类型”,
       机器按double(8个字节)占用的字节空间读取,这样,传入的1、2这两个值被当成了一个数据读出来,按照double的规则进行处理,读出的值为:0×0000000200000001 (此例中使用Big endian序)。

 

       但是,问题出现了,这才读出一个参数,我们还有一个参数到哪里去读呢?

       sumfunf函数在读出第一个参数后,将其值累加至result变量中,在读取第二个参数时,取值的地址范围已经超出了我们传入的数据,然而程序并不会就此出错,恰好在这几个参数之后的堆栈地址中,数据是有效的!

 

       这些数据可被正确的访问,因此,函数在处理第二个参数会继续顺序读取8个字节!这8个字节的值作为第二个参数进行处理,回顾一下双精度浮点数的计算方式,对于0×0000000200000001这样一个数来说,是近乎于0的,因此,最后返回的值是不是为0,就取决于函数从堆栈中顺序读取出来的第二个参数,而这个值是不确定的!我们之所以看到返回值为0.000000,是因为对于这个简单程序而言,在特定的环境下,大部分情况下,读取出来的第二个不定参数在转换为double后,也是接近于0的。

 

   回到printf(“%f”,10/3);的问题来说,产生大家看到的不确定结果也是这个原理。

   对于printf(“%f”, 10/3, 0×40080000);这个能获得3.000000的结果,不妨尝试先自行分析一下。

 

(未完待续)

这篇关于从printf说开去(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/564177

相关文章

printf sprintf fprintf

c语法 1.printf  .   sprintf   .   fprintf 1.1.printf 是把格式字符串输出到标准输出(一般是屏幕,可以重定向)。  1.2.sprintf sprintf,是把格式字符串输出到指定字符串中,所以参数比printf多一个char*。那就是目标字符串地址。 1.3fprintf fprintf, 是把格式字符串输出到指定文件设备中,所

printf打印带颜色的字体和背景

格式如下: printf("\033[字背景颜色;字体颜色m 字符串 \033[0m" ); 例子: printf("\033[1m\033[45;33m HELLO_WORLD \033[0m\n"); 颜色代码: QUOTE:  字背景颜色范围: 40--49                   字颜色: 30—39               40: 黑

printf笔记

1、控制打印颜色 1.1、通用格式: Esc[{attr1};{attr2};...;{attrn}m Esc为转义字符,值为:\033 {attr1}{attr2}{attrn}为属性,属性之间用分号相隔 红色前景输出: \033[31m 1.2、属性列表: 1.2.1、通用格式 0 重置所有属性 1 高亮/加粗 2 暗淡 4 下划线 5 闪烁 7 反转 8 隐藏

Printf 的格式输出探索

#include<stdio.h>int main() //%[flags][width][.prec][hlL]type{ printf("%9d\n",123);//数字输出占据9个字符空间,右对齐printf("%-9d\n",123);//左对齐printf("%+9d\n",123);//^^^^^+123printf("%+-9d\n",123);//+123printf("%-+

使用C标准库中的printf输出

1、增加文件系统调用 对系统调用进行了调整,一是将所有的系统调用实现转移 从头文件转移到C文件中; 二是增加几个有关文件打开和关闭的接口 主要是将系统调用做成单独的app库,这个库可以供其它所有的应用程序使用 2、导入newlib库,并调用 newlib可移植性强,具有可重入特性、功能完备等特点。Newlib的所有库函数都建立在20个桩函数的基础上[2],这20个桩函数完成一些ne

c printf 缓冲区分析

printf行缓冲区的分析总结 2013-08-18 12:29  5222人阅读  评论(7)  收藏  举报   分类: app program(9)  版权声明:本文为博主kerneler辛苦原创,未经允许不得转载。   最近在客户那调试串口的时候,read串口然后printf打印,单字符printf,发现没有输出,后来想起来printf这些

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决 一、CoreMark简介二、创建CubeMX项目2.1 选择MCU2.2 配置CPU时钟2.3 配置串口功能2.4 配置LED引脚2.5 生成CMake项目 三、基础功能支持3.1 支持记录耗时3.2 支持printf输出到串口3.3 支持printf输出

IAR CC2530调试输出printf打印信息

1、很多网友给出的操作是:在General Options-> LibratyConfiguration下选择Smihoste 但是,我用的IAR8.10.3 (8.10.3.40338),根本无此选项,如下图: 2、采用另一种方式,在调试的过程中view->Terminal IO, 即可看到printf打印。

【STM32 HAL】多串口printf重定向

【STM32 HAL】多串口printf重定向 前言单串口printf重定向原理实现CubeMX配置Keil5配置 多串口printf重定向 前言 在近期项目中,作者需要 STM32 同时向上位机和手机发送数据,传统的 printf 重定向只能输出到一个串口。本文介绍如何实现 printf 同时输出到多个串口 单串口printf重定向 原理 为了使用 printf() 函

stm32的UART重定向printf()

1配置好uart 2打开usart.c文件 3在此文件前面添加头文件 4在末尾添加重定向代码 添加的代码 /* USER CODE BEGIN 1 *///加入以下代码,支持printf函数,而不需要选择use MicroLIB //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #if 1//#pragma i