计划要好好修炼c语言水平,在学习过程中发现了很多反常有意思的题目列出来,供大家交流讨论。如果有说错的地方,非常欢迎批评指正。也非常欢迎大家提出问题一起讨论。
一、神奇printf - 压栈弹栈规则
int main()
{
int a = 0;
printf("%d%d%d\n",a,++a,a++);//结果 220
return 0;
}
原理解析:
1.printf函数原型是 printf(const char *format),是一个不定参函数,c语言规定为了提高函数执行效率,不定参函数为从右往左计算;
2.对于不定参依次从右往左进栈。边计算,边压栈,遇到++a或者a,属于左值,先空着,最后更新;遇到i++的,因为它是右值,直接压栈。
分析步骤:
1.a++ //这里++属于右值,直接压栈;
2.++a //属于左值,先计算,值先不给;
3.a //和++a一样,先计算,值先不给;
4.往左没有参数了,挨个给a和++a赋值,已知++一共执行两次,则a和++a结果为2;
5.因为a++属于后操作数,先入栈并且入栈时为0,则值为0。
二、进阶版goto语句
//当时看到这个c语言独有机制感觉很惊奇呀,原来goto还有进化版,可以实现两个函数甚至两个文件之间的跳转
#include <stdio.h>
#include <setjmp.h>
//函数原型
//int setjmp(jmp_buf j);
//void longjmp(jmp_buf j,int i)
jmp_buf buf;
void test(void)
{
printf("in test fun! \n");
longjmp(buf,100);
printf("test fun end! \n");
}
int main()
{
int num = setjmp(buf);
if(num)
{
printf("num = (%d)\n",num);
printf("in main fun if! \n");
}
else
{
printf("in main fun else!\n");
test();
}
return 0;
}
//输出结果
in main fun else!
in test fun!
num = (100)
in main fun if!
原理解析:
1.setjmp(jmp_buf j)必须首先被调用,它表示“使用变量j记录现在的位置”,该函数第一次调用时返回0;
2.调用setjmp后,可以调用longjmp回到之前调用setjmp记录的j的位置并且将第二个参数传回setjmp;
3.当使用longjmp时,j的内容被销毁,简单理解,从哪里来回哪里去并释放当前资源;
4.setjmp和longjmp在c++中变异为更普通的异常处理机制“casch”和“throw”;
5.该功能大多用在异常处理和预防潜在的风险,在某个地方不符合条件时用longjmp带一个状态跳回到原来的位置。
三、函数返回值
因为语言版本更新导致会出现某些练习题不能及时更新,这里及时备注一下
//C89支持无返回类型的函数,默认返回int型 但是到了C99,这种无返回类型的函数是不能编译通过的,会提示 “ISO C++ forbids declaration of 'fun' with no type”的问题
fun(void);
//C99开始函数必须要有返回值 main函数除外
int fun(void);