c语言,有时莫名,有时奇妙----小话c语言(25)

news/2024/11/24 0:14:38/

作者:陈曦

日期:2012-8-17 12:53:12

环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2]  

转载请注明出处


Q1: 为什么下面的输出不按照代码的顺序显示?

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
while(1)
{
fprintf(stdout, "stdout.");
fprintf(stderr, "stderr.");
sleep(1);
}
return 0;     
}

A: 如果把代码改为如下,输出就按照代码顺序显示了:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
setbuf(stdout, NULL);     // set stdout to no buffer                   
while(1)
{
fprintf(stdout, "stdout.");
fprintf(stderr, "stderr.");
sleep(1);
}
return 0;     
}


Q2: 下面的代码中printf函数返回为什么不是1?

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
int main(int argc, char **argv)
{
char *str = "我";
PRINT_D(printf(str));
return 0;     
}

上面的代码保存的编码为UTF-8.


A: 在我的另一篇帖子中已经有详细解释: http://blog.csdn.net/cxsjabcabc/article/details/7528227

如果把代码文件的编码改为其它,答案就出来了: printf返回的是实际输出的字节数。比如http://coolshell.cn/articles/945.html地址的帖子写的是字符数,还有很多地方都不是很清楚得说明是字符数,其实也是一种没有深入调研的模糊解答。



Q3: 下面代码的输出为什么改变了b的数值?

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
int main(int argc, char **argv)
{
int a = 1;       
switch(a)       
{    
int b = 2;           
case 1:  
PRINT_D(b) 
break; 
default: 
PRINT_D(b) 
break; 
} 
return 0;     
}

A: 原因在于c标准规定:switch语句体的复合语句中,位于第一个case或者default标号前面的语句永远不会被执行到。所以,b相当于没有初始化。

另外,我们查看一下汇编,能够得到结论,其实case标号和default标号相当于一个地址,编译器内部会使用jmp, je, jne等语句直接跳到对应位置来执行,而不会分析它前面的初始化过程。

0x00001f10 <main+0>:	push   %ebp
0x00001f11 <main+1>:	mov    %esp,%ebp
0x00001f13 <main+3>:	sub    $0x28,%esp
0x00001f16 <main+6>:	mov    0xc(%ebp),%eax
0x00001f19 <main+9>:	mov    0x8(%ebp),%ecx
0x00001f1c <main+12>:	movl   $0x0,-0x4(%ebp)
0x00001f23 <main+19>:	mov    %ecx,-0x8(%ebp)
0x00001f26 <main+22>:	mov    %eax,-0xc(%ebp)
0x00001f29 <main+25>:	movl   $0x1,-0x10(%ebp)
0x00001f30 <main+32>:	xor    %dl,%dl
0x00001f32 <main+34>:	test   %dl,%dl
0x00001f34 <main+36>:	jne    0x1f52 <main+66>
0x00001f36 <main+38>:	jmp    0x1f38 <main+40>
0x00001f38 <main+40>:	lea    0x1fa0,%eax
0x00001f3e <main+46>:	mov    -0x14(%ebp),%ecx
0x00001f41 <main+49>:	mov    %eax,(%esp)
0x00001f44 <main+52>:	mov    %ecx,0x4(%esp)
0x00001f48 <main+56>:	call   0x1f7a <dyld_stub_printf>
0x00001f4d <main+61>:	mov    %eax,-0x18(%ebp)
0x00001f50 <main+64>:	jmp    0x1f6a <main+90>
0x00001f52 <main+66>:	lea    0x1fa0,%eax
0x00001f58 <main+72>:	mov    -0x14(%ebp),%ecx
0x00001f5b <main+75>:	mov    %eax,(%esp)
0x00001f5e <main+78>:	mov    %ecx,0x4(%esp)
0x00001f62 <main+82>:	call   0x1f7a <dyld_stub_printf>
0x00001f67 <main+87>:	mov    %eax,-0x1c(%ebp)
0x00001f6a <main+90>:	mov    $0x0,%eax
0x00001f6f <main+95>:	add    $0x28,%esp
0x00001f72 <main+98>:	pop    %ebp
0x00001f73 <main+99>:	ret 

注意main+36和main + 38位置的汇编,两条跳转语句会直接找到标号,忽略了前面的代码。

如果把源代码改为如下,依然不能输出3:

int main(int argc, char **argv)
{
int a = 2;       
switch(a)       
{    
int b = 2;           
case 1:  
PRINT_D(b)  
break;
b = 3;
case 2:
PRINT_D(b)
break;
default: 
PRINT_D(b) 
break; 
} 
return 0;     
}

Q4: sizeof运算符里面跟着i++,为什么i没有自增?

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
int main(int argc, char **argv)
{
int i = 1;
PRINT_D(sizeof(i++))
PRINT_D(i)
return 0;     
}

A: 原因在于sizeof在编译期间自动计算出来它的数值,对于i++, 编译器仅仅看到了它的类型,却没有计算它的数值。看看汇编:
0x00001ef0 <main+0>:	push   %ebp
0x00001ef1 <main+1>:	mov    %esp,%ebp
0x00001ef3 <main+3>:	push   %ebx
0x00001ef4 <main+4>:	push   %edi
0x00001ef5 <main+5>:	push   %esi
0x00001ef6 <main+6>:	sub    $0x2c,%esp
0x00001ef9 <main+9>:	mov    0xc(%ebp),%eax
0x00001efc <main+12>:	mov    0x8(%ebp),%ecx
0x00001eff <main+15>:	mov    $0x0,%edx
0x00001f04 <main+20>:	lea    0x1fa7,%esi
0x00001f0a <main+26>:	lea    0x1f94,%edi
0x00001f10 <main+32>:	mov    $0x4,%ebx
0x00001f15 <main+37>:	movl   $0x0,-0x10(%ebp)
0x00001f1c <main+44>:	mov    %ecx,-0x14(%ebp)
0x00001f1f <main+47>:	mov    %eax,-0x18(%ebp)
0x00001f22 <main+50>:	movl   $0x1,-0x1c(%ebp)
0x00001f29 <main+57>:	mov    %edi,(%esp)
0x00001f2c <main+60>:	movl   $0x4,0x4(%esp)
0x00001f34 <main+68>:	mov    %edx,-0x20(%ebp)
0x00001f37 <main+71>:	mov    %ebx,-0x24(%ebp)
0x00001f3a <main+74>:	mov    %esi,-0x28(%ebp)
0x00001f3d <main+77>:	call   0x1f6e <dyld_stub_printf>
0x00001f42 <main+82>:	mov    -0x1c(%ebp),%ecx
0x00001f45 <main+85>:	mov    -0x28(%ebp),%edx
0x00001f48 <main+88>:	mov    %edx,(%esp)
0x00001f4b <main+91>:	mov    %ecx,0x4(%esp)
0x00001f4f <main+95>:	mov    %eax,-0x2c(%ebp)
0x00001f52 <main+98>:	call   0x1f6e <dyld_stub_printf>
0x00001f57 <main+103>:	mov    -0x20(%ebp),%ecx
0x00001f5a <main+106>:	mov    %eax,-0x30(%ebp)
0x00001f5d <main+109>:	mov    %ecx,%eax
0x00001f5f <main+111>:	add    $0x2c,%esp
0x00001f62 <main+114>:	pop    %esi
0x00001f63 <main+115>:	pop    %edi
0x00001f64 <main+116>:	pop    %ebx
0x00001f65 <main+117>:	pop    %ebp
0x00001f66 <main+118>:	ret 
注意main+60位置,它直接将sizeof(i++)得到的数值4放入堆栈,并没有对i自增。



Q5: 为什么形如2["hello"]这样的表达式是什么意思?

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
#define PRINT_CH(charValue)   printf(#charValue" is %c\n", (charValue));
int main(int argc, char **argv)
{
char ch = 2["hello"];
PRINT_CH(ch)
return 0;     
}

A: 2["hello"]等同于"hello"[2], 又等同于 char *str = "hello";  str[2] .  但是,为什么?

因为编译器对于数组访问根本就采用指针加减的计算方法,即2["hello"] == *(2 + "hello"), "hello"是个字符指针, *(2 + "hello")  ==  *("hello" + 2), 所以结论也就出来了。



Q6: 为什么一个整形数据用%f格式输出,结果改变了?

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
#define PRINT_F(floatValue)   printf(#floatValue" is %f\n", (floatValue));
int main()
{
int d = 2;
PRINT_F(d)
return 0;
}

A: 原因在于printf分析%f格式时是从对应地址取出sizeof(float)个字节数据然后当成float格式输出,所以,一般情况下,输出都是错误的。

对于float内部的格式,IEEE 754标准写的很清楚,如果出现类似的问题,可以使用如下结构来简单地验证:

// IEEE 754 single floating number's format(intel little-endian mode)
typedef union
{
// float value
float   f;
// intel bits mode that stands for float value
struct 
{
unsigned int dot     : 23;  // low bits
unsigned int exp     : 8;   // middle bits
unsigned int sign    : 1;   // highest bit
}float_bit;
}float_value;

一个简单的测试代码:

#include <stdio.h>
#define PRINT_D(intValue)   printf(#intValue" is %d\n", (intValue));
#define PRINT_F(floatValue)   printf(#floatValue" is %f\n", (floatValue));
// IEEE 754 single floating number's format(intel little-endian mode)
typedef union
{
// float value
float   f;
// intel bits mode that stands for float value
struct 
{
unsigned int dot     : 23;  // low bits
unsigned int exp     : 8;   // middle bits
unsigned int sign    : 1;   // highest bit
}float_bit;
}float_value;
int main(int argc, char **argv)
{
float_value fv;
fv.float_bit.sign = 1;
fv.float_bit.exp = 128;
fv.float_bit.dot = 0;
PRINT_F(fv.f);
return 0;     
}

输出:

fv.f is -2.000000



作者:陈曦

日期:2012-8-17 12:53:12 

环境:[Mac 10.7.1 Lion Intel i3 支持64位指令 gcc4.2.1 xcode4.2]  

转载请注明出处




http://www.ppmy.cn/news/171781.html

相关文章

开发实用命令和工具----小话c语言(16)

[Mac 10.7.1 Lion Intel-based x64 gcc4.2.1] Q&#xff1a; 有的时候&#xff0c;记得在某个目录下写过某个变量或者其它什么文本形式的东西&#xff0c;但是后来忘记写在哪个文件里了&#xff0c;怎么找到&#xff1f; A&#xff1a; 这个就需要用到grep命令了。它很强大…

小话层次分析法(AHP)

在目标决策领域&#xff0c;有的决策数据信息是量化的&#xff0c;如一个项目的未来收益、消耗成本等&#xff0c;通过对各种信息进行计算可以做出较好的决策&#xff1b;但有的决策数据信息并不全是数字化的&#xff0c;如项目信息为“这个收益更好”、“这个成本更高”这样的…

小话设计模式(番外一)插件模式

插件&#xff08;Plugin&#xff09;模式向用户提供了一种扩展程序的接口&#xff0c;用户可以在程序本体之外&#xff0c;按照指定接口编写插件来为程序增加功能。 可能实际开发中不太会运用到插件模式&#xff0c;但是它确实我们经常会使用到的一种模式。例如CocosBuilder和…

前言----小话c语言(1)

不知道该怎么开头&#xff0c;不过开头的几个字都写了&#xff0c;就继续写下去吧。 看过很多以大话开头的书籍&#xff0c;觉得也不怎么样&#xff0c;觉得还没达到大话的层次&#xff0c;本人本着谦虚的精神&#xff0c;暂且以小话开头吧&#xff1b;可能读者看完&#xff0c…

Git安装与仓库配置(附带)

Git的安装与仓库配置 前期准备安装与配置安装Git注册账户&#xff1a;环境配置配置用户名与邮箱&#xff1a;生成SSH添加SSH配置仓库仓库建立初始化仓库 提交文件操作&#xff1a; Git 的基本语法总结总结小话 前期准备 下载Git安装包&#xff08;根据需求不同选择安装Window/…

小故事

小故事 老和尚背姑娘 小和尚和老和尚下山化缘&#xff0c;走到河边&#xff0c;见一姑娘正发愁没法过河。老和尚对姑娘说&#xff1a;我把你背过去把&#xff0e;姑娘同意事后小和尚目瞪口呆&#xff0c;又不敢问。就这样又走了二十里路&#xff0e;实在忍不住了&#xff0c;就…

嵌入式Linux驱动开发 04:基于设备树的驱动开发

文章目录 目的基础说明开发准备设备树调整驱动程序与测试总结设备树文件内容 目的 前面文章 《嵌入式Linux驱动开发 03&#xff1a;平台&#xff08;platform&#xff09;总线驱动模型》 引入了资源和驱动分离的概念&#xff0c;这篇文章将在前面基础上更进一步&#xff0c;引…

这是一篇儿正儿八经的自我介绍~

你好啊朋友&#xff01;来到这儿我们就认识一下吧&#xff08;我真的不是来唠嗑的&#xff09; 关于我 性别&#xff1a;女年龄&#xff1a;00后坐标&#xff1a;陕西职业&#xff1a;双非本科在读大学生目前我的关注&#xff1a;别人的爱情、自己的财富、什么时候可以彻底解…