Long Luo's Life Notes

每一天都是奇迹

By Long Luo

在开始今天的文章之前,请先看下面一道面试题:

问题: 阅读下面一段代码并回答题目之后的问题:

1
2
3
4
5
struct ALIGN
{
int mA;
int mB;
};

请问在 32 位系统下 sizeof(ALIGN) 的结果是多少?

当然这道题目是难不到广大程序员同学们滴!

在 32 位机器上 int 类型占 4 个字节,Struct ALIGN 里面有 2 个 int 型变量,那么总共就是 8 个字节喽!

Bingo!在这个例子中,sizeof(ALIGN) 的结果的确是 8 。

图1. 结构体对齐

下面,我们把代码修改一下:

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 ALIGN
{
int mA;
int mB;
};

struct ALIGN1
{
int mA;
short mB;
};


int main()
{
cout<<sizeof(short)<<endl;
cout<<sizeof(ALIGN1)<<endl;

getchar();
return 0;
}

请问输出是多少?

阅读全文 »

By Long Luo

之前一篇 深入理解 C/C++ 结构体之二:Structure 的声明、定义、初始化 ,我们已经了解了C++Struct的定义方法和C中有点不一样,而且增加了一种新的类型—Class。从C++的名字我们就可以知道,C++是从C进化而来,“++”就是在C的基础上加了一些东西:面向对象的东西

虽然C++作为一种面向对象语言,要区别于面向过程的C语言,但是在设计时,一个很重要的原则是C++必须向前兼容C,必须是C的超集。这样一来就可以带来好多好处:

第一个嘛,首先呢,C++就可以站在C这个巨人的肩膀上,大量过去用C编写的程序可以不加修改地在C++环境下使用; 第二,把很多C程序员忽悠进C++这个大坑里,为C++之崛起而加班,上了贼船可就由不得你了XD …….

也正是因为这个原因,C++中保留了Struct结构类型,并使得Struct的功能更强大,不仅仅是简单继承C的结构体,而且扩充了Struct,使得它也具有类的特点,那么在C++中,Class和Struct到底有什么区别呢

Talk is cheap, show me the Code!

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
26
27
#include <iostream>

using namespace std;

struct S1
{
char mA;
int mB;
};

class C2
{
char mA;
int mB;
};


int main(void)
{
S1 a;
C2 b;
cout<<sizeof(a)<<&a<<endl;
cout<<sizeof(b)<<&b<<endl;

getchar();
return 0;
}

上面这段代码非常简单,分别定义了一个 Struct 类型和 Class 类型,并输出其大小和地址,我们先看看输出结果:

图1. Struct 和 Class 大小输出

从结果我们可以看出,没啥区别啊!

且慢,再看下面这段代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>

using namespace std;

struct S1
{
char mA;
int mB;
};

class C1
{
char mA;
int mB;
};

struct S2
{
char mA;
int mB;

void foo()
{
cout<<"mA="<<mA<<endl;
cout<<"mB="<<mB<<endl;
}
};

class C2
{
char mA;
int mB;

void foo()
{
cout<<"mA="<<mA<<endl;
cout<<"mB="<<mB<<endl;
}
};


int main(void)
{
S1 a;
C1 b;

S2 c;
C2 d;

cout<<sizeof(S1)<<"\t"<<&a<<endl;
cout<<sizeof(C1)<<"\t"<<&b<<endl;

c.foo();
d.foo();

getchar();
return 0;
}

编译,结果报错了,如下所示:

阅读全文 »

By Long Luo

在上一篇 深入理解 C/C++ 结构体之一: Structure 是为了解决什么问题? 里我们讲了为什么我们要引入 Struct 这个数据类型,我们了解到 Struct 是一种聚合数据类型,是为了用户描述和解释一些事物的方便而提出的, Struct 是一种用户自定义数据类型,如下图 1 所示:

图1. 数据类型

其实从理论上讲,数据类型就是人为制订的如何解释内存中的二进制数的协议,也就是说一个数字对应着一块内存(可能 4 字节,也可能 20 字节),而这个数字的类型则是附加信息,以告诉编译器当发现有对那块内存的操作语句(即某种操作符)时,要如何编写机器指令以实现那个操作。比如两个 char 类型的数字进行加法操作符操作,编译器编译出来的机器指令就和 2 个 long 类型的数字进行加法操作的不一样,也就是所谓的“如何解释内存中的二进制数的协议”。

具体到我们之前的例子来说,只是指定了一种结构体类型,它相当于一个模型,但其中并无具体数据,系统也不为之分配实际的内存单元。为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。

本篇将详细对 Struct 的声明、定义和初始化进行分析。

一、Struct的声明

要了解Struct的声明,我们需要首先了解声明的含义到底是什么?

声明是要求编译器产生映射元素的语句

所谓的映射元素,就是前面介绍过的变量及函数,都只有3个字段:类型栏、名字栏和地址栏(成员变量类型的这一栏就放偏移值)。即编译器每当看到声明语句,就生成一个映射元素,并且将对应的地址栏空着,然后留下一些信息以告诉连接器——此 obj 文件(编译器编译源文件后生成的文件)需要一些符号,将这些符号找到后再修改并完善此 obj 文件,最后链接。

具体到上一回的例子,我们假如在另外一个源文件中需要使用struct ExpectedBoyFriend,那么就需要在该源文件使用之前处使用下面的声明语句:

1
extern struct ExpectedBoyFriend;

二、Struct的定义

上一小节我们了解了声明的定义,那么定义是什么呢?

—定义是要求编译器填充前面声明没有书写的地址栏。 也就是说某变量对应的地址,只有在其定义时才知道。

因此实际的在栈上分配内存等工作都是由变量的定义完成的,所以才有声明的变量并不分配内存。但应注意一个重点,定义是生成映射元素需要的地址,因此定义也就说明了它生成的是哪个映射元素的地址,而如果此时编译器的映射表(即之前说的编译器内部用于记录映射元素的变量表、函数表等)中没有那个映射元素,即还没有相应元素的声明出现过,那么编译器将报错。

在这里我们需要说下 C 和 C++ 在定义 Struct 的区别, 先看下面2段代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

using namespace std;

struct SIMPLE
{
int a;
char b;
float c;
};

SIMPLE x;

再看下面一段源码:

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

struct S0
{
char mName[10];
int mBornYear;
};

typedef struct _S1
{
char mName[10];
int mBornYear;
}
S1;


S0 sa;
S1 sb;

那么上面的代码中对Struct的定义都对了吗?

熟悉C/C++的同学应该能够马上知道第二段的代码错了。

为什么呢?

阅读全文 »

By Long Luo

“关关雎鸠,在河之洲。窈窕淑女,君子好逑”,《诗经》三百篇,开篇就是男女之间的恋情,可见几千年的古人也十分重视爱情。这也难怪,毕竟男女的婚姻是人伦之始,而且含有成家立业的意思。引用生物学的观点来解释,就是“求食求偶是关系到人类生存繁衍的大事”,能不重视么?

在我们的老祖宗还住在山洞里的那个时代,野外看到一个漂亮的女野人,一棍子敲晕,拖进洞里…不过那个年代已经一去不复返了。随着人类的进步,具体到现在这个社会,现代的女人都要求男方高富帅,有车有房…当然按照进化心理学的观点来看,这些东西都代表着男性获取资源的能力,而智人(人类)的后代是很脆弱的,为了繁衍,所以女性是将男性所获取的资源和获取资源的能力置于第一位的。

不过,由于拜国内的房地产所赐,身为一名D丝的话,想要追到一个女孩,也变得异常困难,一方面是硬件上的劣势,比如外表、车、房子、一份体面的工作灯;另外一方面又有软件上的劣势,比如幽默感,人品如何、性格等。付出的服务项目也越来越多,既要送花,要帮女孩做这个做那个表决心,还要送这个送那个表付出。

据说20年后国内将有3000w男性光棍,女孩也就成了卖方市场,眼前这么多追求者,高富帅各方面程度都不一样,应该把哪个放在第一位呢?该怎么选呢?

比如一位美女,就有3位男性追求者,比较来比较去,某天决定先按照“帅”的程度排个序,选一个最“帅”的:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/************************************************************************************
** File: - Z:\work\code\c\Struct\WhyUsingStuct.c
**
** Copyright (C) Long.Luo, All Rights Reserved!
**
** Description:
** WhyUsingStruct.c ---
**
** Version: 1.1
** Date created: 22:25:44,20/12/2012
** Author: Long.Luo
**
** --------------------------- Revision History: --------------------------------
** <author> <data> <desc>
**
************************************************************************************/

#include <stdio.h>

/* Number of the boys */
#define BOYS_NUM (3)

void main()
{
int i, j;

/* Name */
char name[BOYS_NUM][10];

/* height */
int height[BOYS_NUM];

/* rich */
int money[BOYS_NUM];

/* handsome */
int handsome[BOYS_NUM];

/* pointer array of the boys' name */
char *pName[BOYS_NUM];

/* the temporary */
int heightTemp, moneyTemp, handsomeTemp;
char *nameTemp;

for (i = 0; i < BOYS_NUM; i++)
{
pName[i] = name[i];
}

for(i = 0; i < BOYS_NUM; i++)
{
printf("Pls input the Name of the No. %d Boys:", i + 1);
gets(pName[i]);
if (*pName[i] == '\0')
{
gets(pName[i]);
}

printf("Pls input the Height of %s :", pName[i]);
scanf("%d", &height[i]);
printf("Pls input the Money of %s :", pName[i]);
scanf("%d", &money[i]);
printf("Pls input the Handsome of %s :", pName[i]);
scanf("%d", &handsome[i]);
}

/* sort by Height */
/* Only write one item. */
for (i = 0; i < BOYS_NUM - 1; i++)
{
for (j = i + 1; j < BOYS_NUM; j++)
{
if (handsome[i] < handsome[j])
{
nameTemp = pName[i];
pName[i] = pName[j];
pName[j] = nameTemp;

handsomeTemp = handsome[i];
handsome[i] = handsome[j];
handsome[j] = handsomeTemp;
}
}
}

for (i = 0; i < BOYS_NUM; i++)
{
printf("\nThe Boys's info: %s\t, height: %d\t, money: %d\t, handsome: %d\t");
}

getchar();
}

但是上面的代码有很明显缺点:

  1. 变量过多,同一追求者的各个数据无联系,没有整体概念,不便管理;

  2. 操作不便,假如某天想把“”作为第一考虑呢?或者根据不同面采取不同的加权来选择呢?

男人,不止一面!(七匹狼广告)

一个事物往往有很多的特征,但是人们往往去表达事物的时候,不是说特征,而是讲整体。零碎的信息、有时候很难替代一个整体信息结构。

阅读全文 »

By Long Luo

TI的EK-LM3S8962开发板有着比较丰富的外设,由于个人从小对音乐感兴趣,因此利用其中的蜂鸣器外设来实现音乐播放的功能,下面对此进行逐一解析:

先上张开发板的Layout图:

EK-LM3S8962

要实现音乐播放,首先要明白数字音乐是如何播放出来的?

首先需要了解一个事实,那就是我们所听到的音乐只是一系列不同频率的声音按照一定的节奏播放出来。

但是乐音是有特定的频率的,因此我们首先要定义不同的乐音音节:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef  __MUSIC_H__
#define __MUSIC_H__


// 定义低音音名(数值单位:Hz)
#define L1 262 // c
#define L2 294 // d
#define L3 330 // e
#define L4 349 // f
#define L5 392 // g
#define L6 440 // a1
#define L7 494 // b1

// 定义中音音名
#define M1 523 // c1
#define M2 587 // d1
#define M3 659 // e1
#define M4 698 // f1
#define M5 784 // g1
#define M6 880 // a2
#define M7 988 // b2

// 定义高音音名
#define H1 1047 // c2
#define H2 1175 // d2
#define H3 1319 // e2
#define H4 1397 // f2
#define H5 1568 // g2
#define H6 1760 // a3
#define H7 1976 // b3

// 定义时值单位,决定演奏速度(数值单位:ms)
#define T 3600

// 定义音符结构
typedef struct
{
short mName; // 音名:取值L1~L7、M1~M7、H1~H7分别表示低音、中音、高音的
// 1234567,取值0表示休止符
short mTime; // 时值:取值T、T/2、T/4、T/8、T/16、T/32分别表示全音符、
// 二分音符、四分音符、八分音符…,取值0表示演奏结束
}
tNote;

//
typedef struct _tMusic
{
struct tNote;
char cName[20];
}
tMusic;

//
extern void playNote(const tNote * pNote);
extern void displayNoteName(const tMusic * pMusic);


#endif/*__MUSIC_H__*/

然后呢,我们需要歌谱,歌谱是一系列音节按照一定的节奏和时长播放出来:

阅读全文 »
0%