Long Luo's Life Notes

每一天都是奇迹

By Long Luo

在上一篇 深入理解 C/C++ 结构体 <1>: 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__*/

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

阅读全文 »

By Long Luo

linux的文件系统采用单根倒置树结构,在此结构中的最上层是根目录/,然后在此目录下再创建其他的目录。与windows多个根目录不同,Linux只有一个根目录。

文件名称区分大小写。 以.开头的为隐藏文件。 Linux中路径用/来进行分割;windows中使用。 文件有元数据与数据本身两种类型。 默认的基本目录结构如下:

目录 说明 /bin(重点) binary的缩写,存放最常用的命令 /sbin Super User的意思,存放系统管理员使用的系统管理程序 /home(重点) 存放普通用户的主目录,Linux中每个用户都有一个自己的目录,一般是以用户的账号命名 /root(重点) 系统管理员,也称为超级权限者的用户主目录 /lib 系统开机需要的动态连接共享库,作用类似于Windows中的DLL文件。几乎所有的应用程序都要用到这些共享库 /lost+found 一般情况下是空的,当系统非法关机后,这里就存放了一些文件 /etc(重点) 所有的系统管理需要的配置文件和子目录my.conf /usr(重点) 用户的很多应用程序和文件都放在这个目录下,类似于Windows下的program files目录 /boot(重点) 存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件 /proc(别乱动) 是一个虚拟目录,是系统内存的映射,访问这个目录来获取系统信息 /srv(别乱动) service缩写,该目录存放一些服务启动之后需要提取的数据 /sys(别乱动) Linux2.6内核一个很大的变化,该目录安装了2.6内核中新出现的一个文件系统 /tmp 存放一些临时文件 /dev 类似Windows的设备管理器,把所有的硬件用文件的形式存储 /media(重点) Linux系统会自动识别一些设备,如U盘、光驱等,识别后,Linux会把识别的设备挂在到该目录下 /mnt(重点) 此目录是为了让用户临时挂载别的文件系统的,我们可以将外部的存储挂载在/mnt/上,然后进入该目录就可以看里面的内容 /opt 为主机额外安装软件所摆放的目录。如安装ORACLE数据库就可放到该目录下 /usr/local(重点) 这是另一个给主机额外安装软件所安装的目录。一般是通过编译源码方式安装程序 /var(重点) 存放着在不断扩充着的东西,习惯上将经常被修改的目录放在这个目录下,包括各种日志文件 /selinux 全称security-enhanced linux,类似于Windows的360,SELinux是一种安全子系统,它能控制程序只能访问特定文件 文件系统结构总结:

Linux的目录中只有一个根目录/ Linux的各个目录存放的内容是规划好的,不要乱放文件。 Linux是以文件的形式管理设备的,因此Linux系统中一切皆为文件。 Linux的各个文件目录下存放什么内容,需要有一个准确的认识。

在 Linux 系统中,所有内容都是以文件的形式保存和管理的,即「一切皆文件」。普通文件是文件,目录(Windows 下称为文件夹)是文件,硬件设备(键盘、监视器、硬盘、打印机)是文件,就连套接字(socket)、网络通信等资源也都是文件。

linux只有一个根目录,而且文件和目录被组织成一个单根倒置树结构, 此结构最上层是根目录,用“/”表示

根文件系统(rootfs):root filesystem 标准Linux文件系统(如:ext4)

如下图:

关于目录结构,有些比较重要的目录我们要需要记住:

/etc/resolv.conf Linux 系统DNS客户端配置文件,DNS(Domain Name System)在网站的运行中起到了至关重要的作用,其主要负责将网站域名解析为对应的IP地址。

/etc/hostname 主机名配置文件 hostnamectl set-hostname itlaoxin 这个命令会直接修改配置文件

/etc/hosts 设定用户IP与名字(或域名)的对应解析表,相当于本地(局域网内)的DNS解析文件 Linux系统下的这个/etc/hosts类似于C:

/etc/fstab:配置开机设备自动挂载的文件

/etc/inittab:系统启动时设定运行级别等配置的文件

./etc/profile及/etc/bashrc:配置系统的环境变量/别名等的文件

/etc/profile.d:用户登录后执行的脚本所在的目录

/etc/init.d:软件启动程序所在的目录(centos7之前),centos7之后这个目录已经不用了。

/etc/motd:配置用户登录系统之后显示提示内容的文件

/etc/redhat-release:查看Red Hat版本号和名称信息的文件

/etc/sysctl.conf:Linux内核参数设置文件

/var/log:记录系统及软件运行信息文件所在的目录

var/log/secure:用户登录信息日志文件

/var/log/dmesg:记录硬件信息加载情况的日志文件

/proc/cpuinfo 当前cpu相关的信息

/proc/meminfo 当前内存信息

/proc/loadavg 当前平均负载相关的信息

/proc/mounts 当前挂载相关的信息

文件类型

使用命令查看文件,首字母会标记该文件的文件类型,有以下几种类型:

-: 普通文件 d: 目录文件 b: 块文件 c: 字符文件 l: 符号链接文件 p: 管道文件 pipe s: 套字节文件 socket

参考文献

https://www.gnu.org/software/bash/manual/bash.html#Bash-Startup-Files

By Long Luo

一、 问题描述

Java聊天室是用Java程序实现的,由客户端和服务器端组成。先启动服务器端,再启动客户端,服务器验证身份后客户便可登陆聊天室。

对于客户来说: - 注册、登陆和退出聊天室时都有相关提示信息; - 用户应该可以看到所有在线的用户; - 聊天时可以群聊,也可以选择某个聊天对象私聊。

对于服务器来说: - 登录聊天室时必须输入正确的用户名和密码,未注册用户必须先注册; - 可以显示当前使用的端口,IP地址及在线人数; - 可以显示所有用户注册、登陆及退出等信息,且在用户登陆和退出时可以实时刷新在线用户列表 - 可以显示所有聊天记录,并可以将记录保存在文件中。

二、 软件设计

完成这个作业参考了马士兵的Java系列视频及从网络上下载的代码,对其进行了修改和完善,主要是增加了服务器窗口,实时显示相关信息、在线用户列表等。

对于网络聊天器来说,核心思想是基于套接字的编程。在这里,打个小小的比方,我们的程序在Win32环境下表示为一个进程,也可以比喻成一所房子,该进程的套接字就好比是一扇门。我们的服务器,也就是房子的主人,如果他没睡觉的情况下,也就是位于运行状态时,是一直在倾听且欢迎着门外的敲门声的。

客户端程序运行时,会向服务器发起一个连接,即敲服务器家里的门,在程序上是通过创建一个套接字来完成的。当服务器听到了敲门声之后,他会创建一个新的门,专门为这个客户服务,在Java代码上是通过serverSocket.accept()来实现的。这个门也就只为这个客户而开,当客户离开之后,服务器也会将这扇门关闭。

客户端:

  • ChatClient.java,完成客户端窗口的绘制及发起连接、关闭、聊天;

服务器端:

  • ChatServer.java,服务器端,启动服务器端口并进行监听;
  • ServerFrame.java,服务器窗口,主要是服务器窗口绘制;
  • ServerProcess.java,服务器和客户端连接的处理,包括登陆、注册、退出、信息的发送。
阅读全文 »
0%