Archive

Archive for the ‘C++’ Category

APUE 中的 ourhdr.h 头文件

September 17th, 2010 leeing No comments

《UNIX 环境高级编程》中几乎所有的示例代码都包含了 ourhdr.h 文件,这是作者自行写的一个实现,其源代码如下:

#ifndef ourhdr_h
#define ourhdr_h

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAXLINE 4096

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)

typedef void Sigfunc(int);

#if defined(SIG_IGN) && !defined(SIG_ERR)
#define SIG_ERR ((Sigfunc *)-1)
#endif

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))

char *path_alloc(int *);
int open_max(void);
void clr_fl(int, int);
void set_fl(int, int);
void pr_exit(int);
void pr_mask(const char*);
Sigfunc *signal_intr(int, Sigfunc *);

int tty_cbreak(int);
int tty_raw(int);
int tty_reset(int);
void tty_atexit(void);
#ifdef ECHO
struct termios *tty_termios(void);
#endif

void sleep_us(unsigned int);
ssize_t readn(int, void *, size_t);
ssize_t writen(int, const void *, size_t);
int deamon_init(void);

int s_pipe(int *);
int recv_fd(int, ssize_t(*func)(int, const void*, size_t));

int send_fd(int, int);
int send_err(int, int, const char*);
int serv_listen(const char*);
int serv_accept(int, uid_t *);
int cli_conn(const char *);
int buf_args(char *, int (*func)(int, char **));

int ptym_open(char *);
int ptys_open(int, char *);
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, const struct termios *, const struct winsize *);

#endif

int lock_reg(int, int, int, off_t, int, off_t);
#define read_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
#define readw_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len)
#define write_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
#define writew_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)
#define un_lock(fd, offset, whence, len) \
lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)
pid_t lock_test(int, int, off_t, int, off_t);

#define is_readlock(fd, offset, whence, len) \
lock_test(fd, F_RDLCK, offset, whence, len)
#define is_writelock(fd, offset, whence, len) \
lock_test(fd, F_WRLCK, offset, whence, len)

void err_dump(const char*, ...);
void err_msg(const char*, ...);
void err_quit(const char*, ...);
void err_ret(const char*, ...);
void err_sys(const char*, ...);

void log_msg(const char*, ...);
void log_open(const char*, int, int);
void log_quit(const char*, ...);
void log_ret(const char*, ...);
void log_sys(const char*, ...);

void TELL_WAIT(void);
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);

#endif
Categories: C++, Linux Tags:

Linux 环境编程的一些常识

March 9th, 2010 leeing No comments

杂乱地记录一些在 linux 下编程的常识,主要来自<Beginning Linux Programming> 的第一章。

  • /bin: 二进制文件目录,用于存放启动系统时用到的二进制文件。
  • /usr/bin: 用户二进制文件目录,用于存放用户使用的标准程序。
  • /usr/local/bin: 本地二进制文件目录,用于存放特定软件安装的程序。
  • /opt: 可选的操作系统组件和第三方应用可以安装在这个目录。可以将路径添加到PATH。
  • /usr/include: 系统的标准库函数。
  • /usr/include/sys及 /usr/include/linux: 一般放置依赖于特定系统的头文件。

如果没有用 -o 选项告诉编译器将可执行文件放在何处,则会默认将程序放到一个名为a.out的文件里,而a.out的意思是:assembler output,即汇编输出。

库文件的类型:

  • .a :archive 代表传统的静态函数库,类似于windows中的LIB文件,包含在可执行文件中。
    静态库的一个缺点是:如果同时运行多个应用程序,且使用来自同一个函数库时,内存中会有多个相同的拷贝,这将浪费大量的内存和磁盘空间。
  • .so :shared object 代表共享函数库,类似于windows中的dll文件,在程序运行时加载。
    程序使用共享库时的链接方式是这样的:它本身不再包含函数代码,而是引用时可访问的共享代码,当编译好的程序被装载到内存中执行时,函数引用被解析并产生对共享库的调用,如果有必要才被加载到内存中。
    可以使用ldd命令来查看程序所信赖的共享库。

在 gcc 中,参数 -lm 表示链接名为libm的库,并且,编译器会优先选择共享库。而 -L则表示添加库的搜索路径。-c 表示阻止编译器创建一个完整的程序。

$ gcc -c bill.c fred.c                           #生成目标文件
$ ar crv libfoo.a bill.o fred.o                  #生成静态库文件
$ gcc -o program program.o -L. -lfoo             #指定库文件位置

info 的优点是:可以通过链接或者交叉引用来浏览文档并可直接跳转到相关的章节。

> 重定向
>> 将输出附加到一个文件中。

0:标准输入
1:标准输出
2:标准错误

Categories: C++, Linux Tags:

C++ Primer 学习笔记:数组和指针 (2)

March 9th, 2010 leeing No comments

C++ Primer 学习笔记四:数组和指针 (2)

1. 指向const 对象的指针。

如果指针指向const对象,则不允许用指针来改变其所指的const值,C++ 语言强制要求指向const对象的指针也必须具有const特性。

const double *cptr; // cptr may point to a double that is const.

注意这里cptr本身并不是一个const,可以让它指向另一个double对象(可以不是const类型的),但是不能通过cptr来改变所指对象的值。

不能使用void* 指针保存const对象的地址,必须使用const void* 类型的指针保存const对象的地址:

const int universe = 42;
const void *cpv = &universe;

允许把非const对象的地址赋给指向const对象的指针,例如:

double dval = 3.14;
const double *cptr = &dval; // const double* 型的指针可以指向double类型对象。

*cptr = 1.0 // 会产生编译错误,通过它修改对象的值。
const double pi = 3.1415926

cptr = &pi; // 可以给cptr 重新赋值
double cptr1 = &pi; // 编译错误,必须用const double* 型的指针来指向 const double对象。

虽然dval不是const对象,但不允许通过cptr来修改其值。

不能使用指向const对象的指针修改基础对象,然而如果该指针指向的是一个非const对象,则可以用其它方法修改其所指的对象。

将const对象认为是“自以为指向const的指针”可以更好地理解这个概念。

2. const指针。

const指针代表指针本身的值不能修改,即不能修改它所指向的对象。但是指针本身是const的事实没有说明是否能使用该指针修改它所指向的对象的值:指针所指的对象的值能否修改完全取决于该对象的类型。

一般的声明方式是:

int errnum = 0;
int *const curerr = &errnum;

3. 指向const对象的const指针。

const double pi = 3.14159;
const double *const pi_ptr = &pi;

表示:pi_ptr首先是一个const指针,其次它指向double型的const对象。

4.指针和typedef。

使用typedef 经常带来意外的结果,例如:

typedef string *pstring;
const pstring cstr;

因为typedef并不是文本扩展,在这里声明const string时,const修饰的是pstring类型,这是一个指针,因此该声明语句应该是把cstr定义为指向string类型对象的const指针。

所以它等价于下面的代码:

string *const cstr; // 而不是:const string* cstr;

用typedef写const类型定义时,const限定符加在类型名前面容易引起对所定义的真正类型的误解,下面三种声明意义都是相同的:

string s;
typedef string *pstring;
const pstring cstr1 = &s;
pstring const cstr2 = &s;
string *const cstr3 = &s;

习惯于将const置于前面,但是把声明语句重写为置const于类型之后更易于理解。

Read more…

Categories: C++ Tags:

C++ Primer 学习笔记:数组和指针 (1)

March 7th, 2010 leeing 2 comments

C++ Primer 学习笔记三:数组和指针 (1)

1. 现代C++ 中应当尽量使用vector和迭代器类型,避免使用低级的数组和指针。设计良好的程序只有在性能测试时使用vector无法达到性能要求时,才在类实现的内部使用数组和指针。出于遗留系统的原因,还是必须掌握数组的使用方法。

数组的长度是固定的,一经创建就不能添加新的元素。指针则可以像迭代器一样用于遍历和检查数组中的元素。

2. 数组的维数必须用大于等于1的常量表达式定义,此常量表达式只能包含整型字面值常量,枚举常量或者用常量表达式初始化的整型const对象。非const对象和必须到运行时才确定值的const变量不能用于定义数组的维数。

3. 如果没有显式地提供元素初值,则数组元素会像普通变量一样初始化:

  • 在函数体外定义的内置数组,其元素均初始化为0。
  • 在函数体内定义的内置数组,其元素无初始化。
  • 无论数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式的初始化。

4. 不允许数组直接复制或赋值,数组的下标索引应当为size_t类型。

5. 与迭代器不同的是:指针用于指向单个对象,而迭代器只能用于访问容器内的元素。

6. 避免使用未初始化的指针。如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可以避免一个未初始化的指针;如果必须分开赋值,则应当先将指针赋为空值。

7. void* 可以保存任何类型对象的指针,它只支持以下几种操作:

  • 与另一个指针进行比较
  • 向函数传递void* 指针或从函数返回void* 指针
  • 给另一个void* 指针赋值

不允许使用void* 指针操纵它所指向的对象。

8. 指针和引用的比较:

  • 引用总是指向某个对象 ,定义引用时没有初始化是错误的。
  • 赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化就始终指向同一个特定对象(这也是为什么引用必须在定义时初始化的原因)。

例如下面的程序:

int ival = 1024, ival2 = 2048;

int *pi = &ival, *pi2 = &ival2;

pi = pi2 // 现在pi 指向的是ival2。

赋值结束后,pi所指向的ival对象值保持不变,赋值操作修改了pi指针的值,使其指向一个不同的对象。

int &ri = ival, &ri2 = ival2;

ri = ri2; // 将ival2 赋值给ival

这个赋值操作修改了ri引用的值 ival对象,而并非引用本身。赋值后两个引用还是分别指向原来关联的对象,此时这两个对象的值相等。

Read more…

Categories: C++ Tags:

C++ Primer 学习笔记:标准库类型

March 6th, 2010 leeing No comments

C++ Primer 学习笔记二:标准库类型

1. 有一种情况下,必须总是使用完全限定的标准库名字:在头文件中。因为头文件的内容会被预处理器复制到程序中。用#include包含文件时,相当于头文件中的文本将成为我们编写的文件的一部分。如果在头文件中放置using声明,就相当于每个包含此头文件的程序都放置了同一using声明,不论该程序是否需要using声明。而通常,头文件中只应当定义确实必要的东西。

2. 字符串字面值与标准库中的string并不是同一个类型,这是因为历史的原因及C兼容性。
当进行string对象和字符串字面值混合连接操作时,+ 操作符的左右操作数必须至少有一个是string类型的:

string str = "hello " + "world" // 非法
string str0 = "world";
string str1 = "hello" + ", " + str0 // 非法

3. 从标准输入读取string,将:

  • 读取并忽略开头所有的空白字符(如空格,换行符,制表符)
  • 读取字符直到再次遇到空白字符,读取终止。

例如,如果输入为:’        hello world     ‘,则实际保存的是: ‘hello’
一种不常见的初始化方式为:
string str(n,c):将str初始化为字符 c 的n个副本。

4. string.empty() 将返回bool值,判断是否为空串。

5. string:size_type。因为string::size()返回的是string::size_type类型的值,string类类型和许多其它库类型都定义了一些配套类型,通过这些配套类型,库类型的使用就可以与机器无关,size_type定义为与unsigned类型(unsigned int或者unsigned long)具有相同的含义,而且可以保证足够大的能够存储任意string对象的长度。为了使用由string类型定义的size_type类型,必须加上string::来限定所使用的size_type是由string类定义的。
任何存储string的size操作结果的变量必须为string::size_type类型。特别重要的是,不要把size的返回值赋给一个int变量,这是为了避免溢出现象的发生。
对于vector,则应当使用vector::size_type。
并且,习惯用!=而不是 <来编写循环判断条件,如:

for(vector::size_type ix = 0; ix ! = vec.size(); ++ ix) { }

并且,由于string, vector都是可以动态增长的,因此倾向于在每次循环时测试size的当前值,而不是在进入循环前就存储size值的副本。像size() 这样的小库函数一般定义为内联函数,所以每次循环过程中调用它的运行代价是比较小的。

Read more…

Categories: C++ Tags: