2231|7

28

帖子

0

TA的资源

禁止发言

楼主
 

总结几个C语言中的“坑” [复制链接]

总结几个C语言中的“坑”

 

 今天给大家分享几个C语言中的坑。

一、带参数的宏展开顺序

#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)

int main(void)
{
     printf("%s\n",h(f(1,2)));
     printf("%s\n",g(f(1,2)));

     return 0;
}

 

运行结果:

 

12

f(1,2)

 

浅析:

本题中的#运算符可以利用宏参数创建字符串。##运算符和#运算符一样也可以用于类函数宏的替换部分。另外,##还可以用于类对象宏的替换部分,这个运算符可以把两个语言符号组合成单个语言符号,所以该运算符也被成为预处理粘合剂。类参数宏展开遵循一定的顺序,先从外层开始探寻如果遇到#即刻结束探寻,从遇到#处开始一步一步向外层展开,如果没有遇到#探寻到最里层结束探寻,然后一步一步向外层展开。

 

所以printf("%s\n",h(f(1,2)));这条语句的展开顺序为:h(f(1,2))(没有#)  --->>  f(1,2)(到达最里层依然没有#)  ---->>  h(12)  ---->>  12

 

然而printf("%s\n",g(f(1,2)));这条语句的展开顺序是:g(f(1,2))(碰到#即刻结束探寻,开始展开)  ----->>f(1,2)

二、类型转换

#include <stdio.h>
int main(void)
{
int a = -10;
unsigned b = 1;
if(a+b > 0)
printf("a + b > 0\n");
else if (a + b < 0)
printf("a + b < 0\n");
else
printf("a + b = 0\n");
return 0;
}

 

运行结果:

 

a + b > 0

 

浅析:

第一眼看到这道题心里想到这不明摆着 -10 + 1 < 0么,如此easy的题目还要算吗?当程序运行出结果时顿时傻眼了,仔细看了看数据类型发现问题出在了类型的转换上。众所周知,在不同类型的数据进行运算时如果不进行特别的转换那么在数据运算时会先将表示范围较小的数据自动转换成表示范围更广的数,再参与运算,所以本题中会先将int型的a转换成unsigned int型,通过补码运算得知该值为:4294967286,该值加上1会肯定会远大于0,因此输出的是a+b>0

三、溢出问题

程序一:

 

unsigned i;
for (i = 110; i >= 0; i--)
  printf("%u\n",i);

 

运行结果:

死循环

 

浅析:

该题的坑就在于没有注意到unsigned int 的存储范围,当小于零溢出时又会从unsigned int 的最大值开始递减,这就仿佛进入了一个圆环,永远都没有办法找到跳出圆环形跑道的缺口。

 

程序二:

 

#include <stdio.h>
#include <string.h>
int main(void)
{
  char a[1000];
  int i;
  for(i = 0; i < 1000; i++)
    a[i] = -1 -  i;
  printf("%d\n",strlen(a));
  return 0;
}
运行结果:255

 

浅析:这道题看上去很简单但是却暗藏杀机,很少有人能够答对,当i从0开始自增,自增到127时-1 - 127 = -128,而这个数正好是char型变量所能表示的最小数字,i再自增一次就会溢出,变成char所能表示的最大数字,这样又进入了上一题的那个“环”,当i增加到255时-1 - i = 0,此时第一次出现了0,而strlen函数碰到'\0'就结束(不包括),因此输出结果为255。

四、strcpy函数

void test()
{
char str[10],str1[10];
int i;
for(i = 0; i < 10; i++)
  {
    str1[i] = 'a' + i;
  }
strcpy(str,str1);
}
浅析:这段代码第一眼看过去是没问题的,但是再看一眼就能够很轻松找到错误了,strcpy函数是拷贝字符串的函数,它是以'\0'为结尾的,因此当程序运行strcpy这一行时会发生内存非法访问导致程序崩溃。

 

此帖出自ARM技术论坛

最新回复

总结的很好,感谢分享   详情 回复 发表于 2020-5-13 16:28
点赞 关注(1)
 

回复
举报

1000

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

赞一个

此帖出自ARM技术论坛
 
个人签名

没有特别的幸运,就要特别的努力

 
 

回复

22

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
本帖最后由 成风 于 2020-4-29 22:51 编辑

关于第一个宏展开那个例子,尴尬了,又触及到知识盲区了。

然后看了楼主的“浅析”,更尴尬了,没看懂,没跟上楼主的思路。

然后查找资料,终于明白了。

https://www.bbsmax.com/A/MyJxvMr1dn/

 

接着是知其言,知其所以言的思考。也就是为什么规则是这样的,输出结果都是12不是挺好的吗?也方便大家学习理解。

为方便说明理解,设原规则为规则0,都输出12的规则为规则1

                                                    规则0            规则1

意图用宏g(a) 输出 12               g(12)             g(12)

意图用宏g(a) 输出 f(1,2)          g(f(1,2))        做不到。

 

 

 

 

 

 

此帖出自ARM技术论坛
 
 
 

回复

7756

帖子

18

TA的资源

五彩晶圆(高级)

4
 

很多细节,吃过亏下次就知道了。

此帖出自ARM技术论坛
 
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 

回复

4856

帖子

3

TA的资源

版主

5
 

以前 学C的时候,是班里学的最好的,编程是绕脑子的活

此帖出自ARM技术论坛
 
 
 

回复

18

帖子

10

TA的资源

一粒金砂(初级)

6
 

小白路过,问一下。第一个情况,为何要用宏,不用函数?

函数对代码的封装,比宏要好的多,代码的安全性,健壮性也更好。

此帖出自ARM技术论坛
 
 
 

回复

304

帖子

0

TA的资源

一粒金砂(高级)

7
 

很不错的总结,常在搬代码,哪有不踩坑,同问,为啥不用函数,至少看着比较直观。。

此帖出自ARM技术论坛
 
 
 

回复

295

帖子

1

TA的资源

版主

8
 

总结的很好,感谢分享

此帖出自ARM技术论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表