首页 > 编程知识 正文

关于经典面试一年多少秒的思考!启发#define与UL!整形常量的定义

时间:2023-05-05 10:50:51 阅读:222876 作者:2753

关于经典面试一年多少秒的思考!启发#define与UL!

2016年01月11日 13:52:03 Agou_66 阅读数:1935 标签: C语言#defineUL宏定义一年多少秒 更多

个人分类: C语言

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Agou_66/article/details/50496550

预处理-宏定义一讲中,一道经典面试题宏定义一年有多少秒?由此引发知识点的模糊,所以写博客作为记录,也共大家学习!

此题不考虑闰年问题,如下:

 

#define SEC_PER_YEAR 356*24*60*60

 

 

那么问题来了,到底这样定义好不好,我们知道宏定义是在预处理的时候做的,在预处理时他会将字符串SEC_PER_YEAR替换成356*24*60*60。

程序如图:

经过gcc -E 预编译后如图:

结果是:

为了数据的完整加()能让此宏定义更加安全,C语言默认宏定义的整形数字是 int,为了让该宏定义完美运行在8位、16位、32位、64位机器中将宏改进为(这句是很关键的,这就是机器不管是多少位,只要将这个数加上UL就会按照无符号数进行输出,就不会有溢出的的现象了,到底UL和unsigned long int 有何区别?看到下面的解释还是有区别的。UL值只能修饰"整形常量"的,不能修饰非整形常量,到底何为整形常量:3*4*6这个式子是不是整形常量呢?,看下面紫色的文本,“”UL值只能修饰"整形常量"“”的说法不正确,好像与整形常量没有多大关系,只是UL先给谁结合的问题,查百度:

C语言整形常量定义

2014年09月01日 19:16:41 atleks 阅读数:3308

在书中看到这样一道题目:用预处理指令#define声明一个常数,用以表明一年中有多少秒。书中给的答案是:

 

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

 

 

写一个小程序测试此宏定义,如下:

 

#include <stdio.h>

 

#define SECONDS_PER_YEAR (60*60*24*365)UL

 

int main()

{

printf("%lurn", SECONDS_PER_YEAR);

return 0;

}


使用GCC编译时报如下错误: error: ‘SECONDS_PER_YEAR’ undeclared (first use in this function)

查阅一下C99标准(当然,也可以查阅最新的C标准C11,不过我使用的编译器大都是只支持到C99的),在6.4.4节讲到了关于常量的定义,查看其

关于整形常量的定义,如下:

对于十进制整数常量,其定义的形式为:decimal-constant  integer-suffixopt, 在decimal-constant和integer-suffix之间并没有括号,这里的integer-suffix是整形常量的后缀名,譬如:45UL,45*34*23UL这两种情况都可以,但是如果写成(45*34*23)UL就错了,因为在整形常量和后缀名之间加上括号,这样就执行括号内的计算,然后再与UL结合,前面的计算就溢出(前提是int 的位数是16位,不能表示这个数了,如果写成45UL,45*34*23UL,系统首先是23和UL结合,这就认为这个数是unsigned long int 类型,进行了类型提升,符合了C语言算术计算中的类型提升原则,也就是说这种类型的表示的范围被扩大了,前面的数字再乘进来,就会按照unsigned long int类型的范围来表了,)了,再加上UL还有什么意义呢?。所以,文章

开头提到的书中给出的例题的答案是错误的。下面详细讲解一下有关C语言中整形常量的定义。

在C语言中的整形常量,关于其默认类型,参考C99标准中6.4.4.1节:

The type of an integer constant is the first of the corresponding list in which its value can be represented.

即,C语言中一个十进制整数会被默认为int类型,如果长度超出int表示范围,而又在long int的范围之内,则会被认为是long int类型,如果long int

也表示不了,则会被认为是long long int类型。对于很多在常见的32位系统上编程的人来说可能结尾处加UL的作用并不明显,因为int和long都是32位,

但是对于嵌入式环境编程的人来说,这个就很有必要了,因为程序跑的环境有可能是16位的,且int是16位而long是32位的,这个时候加UL后缀就很有必要了。

对于宏定义:

 

#define SECONDS_PER_YEAR 60 * 60 * 24 * 365

则60*60*24*365的结果会被认为是一个int,如果是16位的环境则会溢出。如果在结尾加上UL,如下:

 

 

#define SECONDS_PER_YEAR 60 * 60 * 24 * 365UL

根据上述C99标准中有关整形常量定义可以知道其实UL首先是与365结合,即365会被认为是一个unsigned long类型的数,而根据C语言算术计算中的类型提升

 

原则可以知道整个算式的计算结果也会被认为是UL类型的。

对于宏定义:

 

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

之所以会报错是因为,UL找不到结合的数字,在16位的环境中,先计算60×60×24×365,则会溢出,然后再将这个溢出的值与UL结合,已经没有意义,故编译

 

会报错。

 

参考资料:

[1]   C99标准

[2]   http://bbs.21ic.com/icview-196689-1-1.html

[3]   http://blog.csdn.net/ropenyuan/article/details/6157589

):

 

#define SEC_PER_YEAR (356*24*60*60)UL

 

在去编译,你会发现出错了!错误是  error: expected ‘,’ or ‘;’ before ‘UL’明明对着呢,为啥会错呢!就因为UL,UL告诉编译器(是编译器非预编译器)此时是unsigned long int类型,U和L是 “整数常量” 的后缀修饰,因此UL只能修饰整数常量本身;所以将宏写为:

 

#define SEC_PER_YEAR (356*24*60*60UL)

 

 

此时在编译发现完美运行,这回美了,定义出个完美的宏,错!在C51编译器中int是16

位的,int最大值是32767,然而356*24*60 是int类型已经溢出,所以依然得不得完美的宏。所以次宏改为:

 

#define SEC_PER_YEAR (1UL*356*24*60*60)

 

 

这次终于完美了;1UL保证以后的数据不会在任何情况下溢出!(为什么要加1UL呢?,我认为上面文本中紫色的文本内容讲的有道理。)

 

由于我没有51编译器,下面给个cxdhy的关于宏定义数据溢出的测试结果笔记链接:

                                 阿树儒雅的紫菜的笔记

通过笔记也可以加深对数据溢出的理解!

 

 

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。