Long Luo's Life Notes

每一天都是奇迹

By Long Luo

一、引言

在上一篇 深入剖析printf函数(上):如何不借助第三方库在屏幕上输出”Hello World”? 里,我们已经实现了用汇编语言在屏幕上输出了“Hello World”, 迈出了万里长征的第一步,但是我们知道实际的printf的功能是十分强大的,它和scanf一样属于标准输入输出的一种格式化函数,我们一般是这样使用它的:

1
printf()的基本形式:printf("格式控制字符串",变量列表);

二、格式化输出

printf()函数是格式输出函数,请求printf()打印变量的指令取决与变量的类型.

例如,在打印整数是使用%d符号,在打印字符是用%c符号.这些符号被称为转换说明.因为它们指定了如何不数据转换成可显示的形式

下列列出的是ANSI C标准printf()提供的各种转换说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
转换说明及作为结果的打印输出
%a 浮点数、十六进制数字和p-记数法(C99)
%A    浮点数、十六进制数字和p-记法(C99)
%c    一个字符 
%d    有符号十进制整数 
%e    浮点数、e-记数法
%E    浮点数、E-记数法
%f    浮点数、十进制记数法  
%g    根据数值不同自动选择%f或%e.
%G    根据数值不同自动选择%f或%e.
%i 有符号十进制数(与%d相同)
%o    无符号八进制整数
%p    指针    
%s    字符串
%u    无符号十进制整数
%x    使用十六进制数字0f的无符号十六进制整数 
%X    使用十六进制数字0f的无符号十六进制整数
%%    打印一个百分号

三、形参列表的读入

printf函数的参数列表是如下的形式:

1
int printf(const char *fmt, ...)

类似于上面参数列表中的token:…,这个是可变形参的一种写法。当传递参数的个数不确定时,就可以用这种方式来表示。

但是电脑比程序员更笨,函数体必须知道具体调用时参数的个数才能保证顺利执行,那么我们必须寻找一种方法来了解参数的个数。

让我们先回到代码中来:

阅读全文 »

By Long Luo

前言

—“你为什么要去登珠穆朗玛?”

当美国《纽约时报》记者问英国登山家乔治·马洛里。

—“Because it is there(因为山在那里)。”

一、 内核的诱惑

会当凌绝顶,一览众山小。

内核,是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性

几十年来,内核以它那深深的魅力吸引着无数的码农为之倾倒,一代又一代的码农们从青青葱葱走向硕果累累,从风华正茂走向耄耋之年,也走出了现在多姿多彩的世界。

内核就像一位风姿卓约的美女,多少码农欲一亲芳泽而不得。Linux内核是庞大复杂的,超过 600 万行的代码,就如同珠穆朗玛峰一样那样让人望而生畏。初学者一踏入,绝大多数会不自觉地迷失在这座庞大的迷宫里。

二、用printf撕开一个小小的口子…

作为一名内核小白,我也期望着那天能登上Linux内核这座高峰,一览其风采,但高原反应可不是闹着玩的。 既然等不了珠穆朗玛峰,那就先试试攀登莲花山吧…

每一位初学者都学习过下面这个例子,

—没看过? —拖出去,XX了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/************************************************************************************
** File: - Z:\code\c\LLprintf\print0.1\LLapp.c
**
** Copyright (C), Long.Luo, All Rights Reserved!
**
** Description:
** LLapp.c
**
** Version: 0.1
** Date created: 21:30:00,10/01/2013
** Author: Long.Luo
**
** --------------------------- Revision History: --------------------------------
** <author> <data> <desc>
**
************************************************************************************/

#include <stdio.h>

int main(void)
{
printf("Hello, World!\n");

return 0;
}

我们通过调用 printf 就可以实现在屏幕上输出一段字符? —为什么呢? —假如我们不用 printf ,怎么做呢?

printf里面蕴含着什么样的秘密呢?

阅读全文 »

By Long Luo

在系列之三 深入理解 C/C++ 结构体之三:借我一双慧眼吧,让我把C++中Class(类)和Struct(结构体)看个清清楚楚明明白白… ,我们在文章的结尾留了一个悬念:

我们了解到C语言规范是struct里面是不能有函数体的,但是在应用中假如struct中没有函数的话,我们会遇到很多问题,第一数据往往是依附于函数来进行操作的;其二是我们需要用C来实现面向对象的思想

比如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

struct FuncInside
{
int mA;
void func()
{
printf("Hello, function inside!\n");
}
};


void main(void)
{
struct FuncInside f;

f.mA = 99;
f.func();

getchar();
}

编译会提示:

1
1>e:\learn\vs\struct\struct\funcpointer.c(7) : error C2032: “func”: 函数不能是 struct“FuncInside” 的成员

那么这个问题应该如何解决呢?

一刹那,一句话在脑海中闪现,“指针是C语言的精华。

啊哈,灵机一动!

阅读全文 »

By Long Luo

上一回 深入理解 C/C++ 结构体之五:无即是有,没有成员变量的 Struct ,我们在文章的结尾留了一个悬念:

—为什么0元素数组在classstruct结构体之外定义就是错误的,而在classstruct中定义就是Okay的,那么结构体中的0元素数组意义何在

打个通俗的比喻,比如一个部门,有部门经理、PM、以及数量众多的苦逼程序猿们,某天部门接到一个项目,于是乎,拉出一个PM及数量未知的程序猿们,开工了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

using namespace std;

struct Department
{
int Manager;
int PM;
int ProgrammerNo[0];
};


int main(void)
{
Department *pt = NULL;
int Num = 5;
pt = (Department *)malloc(sizeof(Department) + sizeof(int) * Num);

pt->ProgrammerNo[0] = 006;
pt->ProgrammerNo[1] = 99;


getchar();
return 0;
}

做一个项目,程序猿的数量是变化的,因此我们也就知道

struct0元素数组意义就是可以作数量未知的扩展,所以也称为flexible arrays

通过系列之五和之六,我们了解了0元素数组的意义。在下一篇中我们将试图揭开struct最复杂和最难的部分:Struct中的函数和函数指针

不要走开,后面更精彩!

  • Updated by Long Luo at 2016-6-11 04:42:01 @Shenzhen, China.

By Long Luo

在上一篇 深入理解 C/C++ 结构体之四:以空间换时间,结构体中的成员对齐之道 中,我们学习了 struct 的内存对齐的前世今生。

在开始本篇之前,想问大家一个问题:

---0是什么?
---呵呵,就是没有呗!
---那好,这5块钱拿去,就当抵我上次向你借的500块钱。
---什么?这哪和哪啊!这不一样
---可是你自己说的, 0就是“没有”。
---我说不清,反正不行,你必须还我500.

0是什么? 起什么作用呢? 为什么500 ≠ 5?

这节我们来讨论0的作用

例如,500块钱,它后面0起到了什么作用呢?

500 的0,表示十和个位“没有”。虽说“没有”,但这个0却不能省略。因为如果省略了0,一件500块的衣服,你只给5块,小心遭到暴打。

那原因是什么呢?

按位计数法中,数位具有很重要的意义。即使十位的数“没有”,也不能不写数字。这时就轮到0出场了,即0的作用就是占位。换言之,0占着一个位置以保证数位高于它的数字不会产生错位。

正因为有了表示“没有”的0,数值才能正确地表现出来。可以说在按位计数法中0是不可或缺的。

打住,这和我们讲的struct有什么关系?

当然有关系了,请问下面这段代码输出的是什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

using namespace std;

struct NoMember
{

};

int main(void)
{
cout<<"The size of the struct NoMem is:"<<endl;
cout<<sizeof(NoMember)<<endl;

getchar();
return 0;
}

—是0呢? —还是1?2?3?

想必大部分人还是说不出来的,那我们先看看输出结果:

阅读全文 »
0%