嵌入开发

Linux中的exit()与_exit()

作为系统调用而言,_exit和exit是一对孪生兄弟,它们究竟相似到什么程度,我们可以从Linux的源码中找到答案:

#define __NR__exit __NR_exit 
"__NR_"是在Linux的源码中为每个系统调用加上的前缀,请注意第一个exit前有2条下划线,第二个exit前只有1条下划线。

这时随便一个懂得C语言并且头脑清醒的人都会说,_exit和exit没有任何区别,但我们还要讲一下这两者之间的区别,这种区别主要体现在它们在函数库中的定义。_exit在Linux函数库中的原型是:

#i nclude<unistd.h>void _exit(int status);
和exit比较一下,exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中,从名字上看,stdlib.h似乎比 unistd.h高级一点,那么,它们之间到底有什么区别呢?

_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。

exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。

在Linux的标准函数库中,有一套称作"高级I/O"的函数,我们熟知的printf()、fopen()、fread()、fwrite()都在此列,它们也被称作"缓冲I/O(buffered I/O)",其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符和文件结束符EOF),再将缓冲区中的内容一次性写入文件,这样就大大增加了文件读写的速度,但也为我们编程带来了一点点麻烦。如果有一些数据,我们认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时我们用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失,反之,如果想保证数据的完整性,就一定要使用exit()函数。

请看以下例程:

#i nclude<stdlib.h>
main()
{
printf("output begin");
printf("content in buffer");
exit(0);
}

编译并运行:

$gcc exit2.c -o exit2
$./exit2
output begin
content in buffer
#i nclude
main()
{
printf("output begin");
printf("content in buffer");
_exit(0);
}

编译并运行:
$gcc _exit1.c -o _exit1
$./_exit1
output begin

在Linux中,标准输入和标准输出都是作为文件处理的,虽然是一类特殊的文件,但从程序员的角度来看,它们和硬盘上存储数据的普通文件并没有任何区别。与所有其他文件一样,它们在打开后也有自己的缓冲区。

此外,另外一种解释:
简单的说,exit函数将终止调用进程。在退出程序之前,所有文件关闭,缓冲输出内容将刷新定义,并调用所有已刷新的“出口函数”(由atexit定义)。

_exit:该函数是由Posix定义的,不会运行exit handler和signal handler,在UNIX系统中不会flush标准I/O流。

简单的说,_exit终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数。

共同:

不管进程是如何终止的,内核都会关闭进程打开的所有file descriptors,释放进程使用的memory!

note:

在由‘fork()’创建的子进程分支里,正常情况下使用‘exit()’是不正确的,这是因为使用它会导致标准输入输出的缓冲区被清空两次,而且临时文件被出乎意料的删除(译者注:临时文件由tmpfile函数创建在系统临时目录下,文件名由系统随机生成)。

在C++程序中情况会更糟,因为静态目标(static objects)的析构函数(destructors)可以被错误地执行。

还有一些特殊情况,比如守护程序,它们的父进程需要调用‘_exit()’而不是子进程;适用于绝大多数情况的基本规则是,‘exit()’在每一次进入‘main’函数后只调用一次。

在由‘vfork()’创建的子进程分支里,‘exit()’的使用将更加危险,因为它将影响父进程的状态

注:exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1,标准C里有EXIT_SUCCESS和EXIT_FAILURE两个宏,用exit(EXIT_SUCCESS);可读性比较好一点。

 

 

from:Linux社区  作者:yzykhq

vim自动补全 ZZ

http://hi.baidu.com/515314237/blog/item/08a4f0f8d840a853242df245.html

autocomplpop.vim : Automatically open the popup menu for completion

http://www.vim.org/scripts/script.php?script_id=1879

介绍

用惯一些IDE的朋友,一开始可能不习惯Vim的自动补全,主要是每次都要按下一个组合键才会出现提示,而不是像IDE里面那样只要输入了某个操作符就会触发自动补全。

autocomplpop.vim 这个插件就可以很好的解决这个问题。
基本使用

首先访问链接[1],下载 autocomplpop.vim 后,放到Vim文件目录下的plugin目录中,然后重启一下 vim 就会发现在编码时会自动的弹出提示了。

打开 autocomplpop.vim ,可以再 DOCUMENT 部分看到使用方式与一些设置。
增加智能提示触发命令

该插件的默认设置可以完成一些基本的提示,但是每种语言都不同,需要触发 全能 (omni) 补全 的操作符也不同,所幸 autocomplpop 可以让我们自己定制触发的命令模式,这样就可以实现无限扩展以达到自己的需求。

autocomplpop已经实现了部分语言的自动全能补全,比如 ruby文件中按 “.” 或者 “::” 就会触发全能补全,看一下改插件中已经实现的一些语言

” Which completion method is used depends on the text before the cursor. The
” default behavior is as follows:

” 1. The keyword completion is attempted if the text before the cursor
” consists of two keyword character.
” 2. The filename completion is attempted if the text before the cursor
” consists of a filename character + a path separator + 0 or more
” filename characters.
” 3. The omni completion is attempted in Ruby file if the text before the
” cursor consists of “.” or “::”. (Ruby interface is required.)
” 4. The omni completion is attempted in Python file if the text before
” the cursor consists of “.”. (Python interface is required.)
” 5. The omni completion is attempted in HTML/XHTML file if the text
” before the cursor consists of “<” or “
” 6. The omni completion is attempted in CSS file if the text before the
” cursor consists of “:”, “;”, “{“, “@”, “!”, or in the start of line
” with blank characters and keyword characters.

光有这些我们可能还不能满足,下面我们试着自己来添加一些触发命令
加入PHP的全能提示触发命令

php 中 一般是会在 “$”, “->“, “::” 后需要出现自动补全,在 .vimrc 中加入以下代码:

if !exists(‘g:AutoComplPop_Behavior’)
let g:AutoComplPop_Behavior = {}
let g:AutoComplPop_Behavior['php'] = []
call add(g:AutoComplPop_Behavior['php'], {
\ ‘command’ : “\\“,
\ ‘pattern’ : printf(‘\(->\|::\|\$\)\k\{%d,}$’, 0),
\ ‘repeat’ : 0,
\})
endif

这样就可以了。

注意,某些时候,可能会在第一次按下触发补全的操作符时停顿一会,这可能是因为可匹配的项目过多,Vim正在索引,过后就会快了。

在 Vim 中实现括号自动补全

流行的 IDE 的编辑器,诸如 Eclipse,都提供了括号自动补全的功能,相当的方便。可惜 Vim 默认情况下并没有提供这样的功能,那就只有自己来写了。

将下面的代码加入到 ~/.vimrc 中,重启 Vim,即可:

:inoremap ( ()i
:inoremap ) =ClosePair(‘)’)
:inoremap { {}i
:inoremap } =ClosePair(‘}’)
:inoremap [ []i
:inoremap ] =ClosePair(‘]’)
:inoremap < <>i
:inoremap > =ClosePair(‘>’)

function ClosePair(char)
if getline(‘.’)[col('.') - 1] == a:char
return “\”
else
return a:char
endif
endf
这样,写代码的时候不再担心会丢掉右边的括号了,尤其是函数嵌套的时候

著名编程语录

一个好的程序员应该是那种过单行线都要往两边看的人。

– Doug Linder, 系统管理员

任何一个工具,它的一个最重要的、同时也是最难以做到的方面就是对那些学习使用这个工具的人在使用习惯上的影响。如果这个工具是一种编程语言,那么,这种影响——不管我们是否喜欢——将是一种思考习惯上的影响。

– Edsger Dijkstra, 计算机科学家

抽象化是一种非常的不同于模糊化的东西 … 抽象的目的并不是为了模糊,而是为了创造出一种能让我们做到百分百精确的新语义。

– Edsger Dijkstra

除数学外,对本土语言的异常的精通会是一个计算机程序员的最宝贵的财富。

– Edsger Dijkstra

C语言很容易让你犯错误;C++看起来好一些,但当你用它时,你会发现会死的更惨。

– Bjarne Stroustrup,C++语言的创始人

评论:解决问题大多数都很容易;找到问题出在哪里却很难。

– 无名

看看目前我们的计算机编程上的这种糟糕的状态,软件开发很显然仍然处于一种黑色艺术状态,仍然毫无工程规范可言。

– 比尔克林顿,美国前总统

长久以来一个问题一直困扰着我,为什么有些东西如此昂贵,如此的高科技,却毫无用处,就像我知道的,计算机虽然是台笨机器,却有能力做出难以置信的智能事情,而程序员虽然是一些聪明的人,但却老是做难以置信的傻事情。他们呀,简言之,是对绝配。

– Bill Bryson, 作家, 出自《Notes from a Big Country》

给与足够的眼球,所有的Bugs都很容易发现(例如,大量的beta测试,结对开发,所有的问题都能很快的发现和修复)

– Eric S. Raymond, 程序员,开源软件的倡导者, 出自《The Cathedral and the Bazaar》

高质量的代码就是对程序自己最好的注释。当你打算要添加注释时,问问自己,“我如何能改进编码以至于根本不需要添加注释?”改进你的代码,然后才是用注释使它更清楚。

– Steve McConnell, 软件工程师,作家, 出自 《Code Complete》

嘿,编译通过了!装包吧!

– 无名

任何优秀的大软件里面都是一个优秀的小程序。

– Charles Antony Richard Hoare, 计算机科学家

我们应该注意到,没有一个受过伦理教育的软件工程师会同意开发出“摧毁巴格达”的程序。然而基本的职业道德却可以要求他们开发出“摧毁城市”的程序,巴格达只是这个程序的一个参数。

– Nathaniel S.Borenstein, 计算机科学家

管理程序员就像是在放养一群猫。

– 无名

用代码行数来评估程序的开发进度,就好比是拿重量来评估一个飞机的建造进度。

– 比尔盖茨,前微软总裁

在一种编程语言中,即使有再多的好程序被诋毁指责,也要比被说成完美无缺好 — 好的多。

– Bjarne Stroustrup, 出自 《The Design and Evolution of C++》

程序应该是写给其他人读的,让机器来运行它只是一个附带功能。

– Harold Abelson and Gerald Jay Sussman,计算机科学家和作者,出自《The Structure and Interpretation of Computer Programs》

真正的程序员从来不注释他们的代码。如果你做不到这样,也就说明你不能使你的程序易于理解。

– 无名

简单是稳定的前提。

– Edsger Dijkstra

C语言 — 这是一种既有汇编语言强大的功能,又有汇编语言的灵活性的编程语言。

– 无名

最初90%的开发工作将会用去你最初90%的开发时间。剩下的10%的开发量将会用去你另外一个90%的开发时间。

– Tom Cargill, 贝尔实验室的面向对象编程专家

对于增加一个功能点所付出的代价,你要明白的很重要的一点就是,它不仅仅指开发这个功能所消耗的时间。它同时还包括带来的额外的给以后扩展造成的困难。不错,任何的功能特性都是能实现的——只要有足够的时间。除了这些将来会出现的问题外,你最终还会使你的程序变得脆弱,最终连一个绝对简单的功能都越来越难以和现有的混乱的web结合起来。应对此问题的办法是你应只接受那些不会导致冲突的功能。

– John Carmack, 计算机游戏开发

性能的关键是精简,而不是一堆的优化用例。除非有真正显著的效果,否则一定要忍住你那些蠢蠢欲动的小微调的企图。

– Jon Bently 和 M. Douglas McIlroy, 同为贝尔实验室的科学家

用C写的最后的一个好东西就是舒伯特的第九交响乐。

– Erwin Dieterich, 程序员

使用C++的问题就在于 … 这种语言有一种很大的脾气,在你想做任何事情之前你必须把所有的知识都掌握才行。

– Larry Wall, Perl语言的开发者

开发的越早,程序花费你的时间越长。

– Roy Carlson, 威斯康星州大学

原型的价值就在于它对你的教育,而不是代码本身。

– Alan Cooper, 软件作者, 出自《The Inmates are Running the Asylum》

世上只有两种编程语言:一种是总是被人骂的,一种是从来没人用的。

– Bjarne Stroustrup

世上有两种设计软件的方法。一种是尽量的简化,以至于明显没有任何缺陷。而另一种是尽量复杂化,以至于找不到明显的缺陷。

– Charles Antony Richard Hoare

丑陋的程序和丑陋的吊桥一样:他们都容易坍塌,因为人类(尤其是工程师们)的审美定义跟人们对复杂事物的处理和理解密切相关。一种编程语言如果不能使你写出优美的代码,那它也就不能使你写出好的程序。

– Eric S.Raymond

数周的编程能省掉你几个小时的计划时间。

– 无名

当一种能够让程序员通过简单的英语来编程的编程语言诞生后,你会发现程序员们都不会说英语。

– 无名

Ubuntu 10.04下C程序中集成Python

测试环境:Ubuntu 10.04

#include <stdio .h>
#include <python .h>
int main(int argc, char * argv[])
{
  // initialize the interpreter
  Py_Initialize();
  // evaluate some code

  PyRun_SimpleString("import sys\n");
  //ignore line wrap on following line
  PyRun_SimpleString("sys.stdout.write(‘Hello from an embedded Python Script\\n’)\n");
  // shut down the interpreter
  Py_Finalize();
  return 0;
}

编译:

$gcc Listing1.c -I/usr/include/python2.6 -lpython2.6

编译成.so

$gcc -c -fPIC Listing2.c -I/usr/include/python2.6
$gcc -shared Listing2.o -o libcrypto.so -lpython2.6

 

from:oulan.com

Linux c 线程互斥

1.Linux“线程”

进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型。Linux是一种“多进程单线程”的操作系统。Linux 本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。
大 家知道,进程是资源分配的单位,同一进程中的多个线程共享该进程的资源(如作为共享内存的全局变量)。Linux中所谓的“线程”只是在被创建时 clone了父进程的资源,因此clone出来的进程表现为“线程”,这一点一定要弄清楚。因此,Linux“线程”这个概念只有在打冒号的情况下才是最 准确的。

目前Linux中最流行的线程机制为LinuxThreads,所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号 处理在内的线程管理机制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)负责开发完成,并已绑 定在GLIBC中发行,它实现了一种BiCapitalized面向Linux的Posix 1003.1c “pthread”标准接口。Linuxthread可以支持Intel、Alpha、MIPS等平台上的多处理器系统。

按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令:

gcc -D -REENTRANT -lpthread xxx. c

其中-REENTRANT宏使得相关库函数(如stdio.h、errno.h中函数) 是可重入的、线程安全的(thread-safe),-lpthread则意味着链接库目录下的libpthread.a或libpthread.so文 件。使用Linuxthread库需要2.0以上版本的Linux内核及相应版本的C库(libc 5.2.18、libc 5.4.12、libc 6)。

2.“线程”控制

线程创建

进程被创建时,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create:

pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);

start_routine为新线程的入口函数,arg为传递给start_routine的参数。

每个线程都有自己的线程ID,以便在进程内区分。线程ID在pthread_create调用时回返给创建线程的调用者;一个线程也可以在创建 后使用pthread_self()调用获取自己的线程ID:

pthread_self (void) ;

线程退出

线程的退出方式有三:
(1)执行完成后隐式退出;
(2)由线程本身显示调用pthread_exit 函数退出;
pthread_exit (void * retval) ;
(3)被其他线程用pthread_cance函数终止:
pthread_cance (pthread_t thread) ;

在某线程中调用此函数,可以终止由参数thread 指定的线程。

如果一个线程要等待另一个线程的终止,可以使用pthread_join函数,该函数的作用是调用pthread_join的线程将被挂起直到 线程ID为参数thread的线程终止:

pthread_join (pthread_t thread, void** threadreturn);

 

3.线程通信

线程互斥
互斥意味着“排它”,即两个线程不能同时进入被互斥保护的代码。Linux下可以通过pthread_mutex_t 定义互斥体机制完成多线程的互斥操作,该机制的作用是对某个需要互斥的部分,在进入时先得到互斥体,如果没有得到互斥体,表明互斥部分被其它线程拥有,此 时欲获取互斥体的线程阻塞,直到拥有该互斥体的线程完成互斥部分的操作为止。

下面的代码实现了对共享全局变量x 用互斥体mutex 进行保护的目的:

int x; // 进程中的全局变量
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //按缺省的属性初始化互斥体变量mutex
pthread_mutex_lock(&mutex); // 给互斥体变量加锁
… //对变量x 的操作
phtread_mutex_unlock(&mutex); // 给互斥体变量解除锁

线程同步

同步就是线程等待某个事件的发生。只有当等待的事件发生线程才继续执行,否则线程挂起并放弃处理器。当多个线程协作时,相互作用的任务必须在一 定的条件下同步。

Linux下的C语言编程有多种线程同步机制,最典型的是条件变量(condition variable)。pthread_cond_init用来创建一个条件变量,其函数原型为:

pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);

pthread_cond_wait和pthread_cond_timedwait用来等待条件变量被设置,值得注意的是这两个等待调用需要 一个已经上锁的互斥体mutex,这是为了防止在真正进入等待状态之前别的线程有可能设置该条件变量而产生竞争。pthread_cond_wait的函 数原型为:

pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);

pthread_cond_broadcast用于设置条件变量,即使得事件发生,这样等待该事件的线程将不再阻塞:

pthread_cond_broadcast (pthread_cond_t *cond) ;

pthread_cond_signal则用于解除某一个等待线程的阻塞状态:

pthread_cond_signal (pthread_cond_t *cond) ;

pthread_cond_destroy 则用于释放一个条件变量的资源。

在头文件semaphore.h 中定义的信号量则完成了互斥体和条件变量的封装,按照多线程程序设计中访问控制机制,控制对资源的同步访问,提供程序设计人员更方便的调用接口。

sem_init(sem_t *sem, int pshared, unsigned int val);

这个函数初始化一个信号量sem 的值为val,参数pshared 是共享属性控制,表明是否在进程间共享。

sem_wait(sem_t *sem);

调用该函数时,若sem为无状态,调用线程阻塞,等待信号量sem值增加(post )成为有信号状态;若sem为有状态,调用线程顺序执行,但信号量的值减一。

sem_post(sem_t *sem);

调用该函数,信号量sem的值增加,可以从无信号状态变为有信号状态。

 

4.实例

下面我们还是以名的生产者/消费者问题为例来阐述Linux线程的控制和通信。一组生产者线程与一组消费者线程通过缓冲区发生联系。生产者线程 将生产的产品送入缓冲区,消费者线程则从中取出产品。缓冲区有N 个,是一个环形的缓冲池。

#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE 16 // 缓冲区数量

struct prodcons
{
// 缓冲区相关数据结构
int buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/
pthread_mutex_t lock; /* 互斥体lock 用于对缓冲区的互斥操作 */
int readpos, writepos; /* 读写指针*/
pthread_cond_t notempty; /* 缓冲区非空的条件变量 */
pthread_cond_t notfull; /* 缓冲区未满的条件变量 */
};

/* 初始化缓冲区结构 */
void init(struct prodcons *b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}

/* 将产品放入缓冲区,这里是存入一个整数*/
void put(struct prodcons *b, int data)
{
pthread_mutex_lock(&b->lock);
/* 等待缓冲区未满*/
if ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait(&b->notfull, &b->lock);
}

/* 写数据,并移动指针 */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos > = BUFFER_SIZE)
b->writepos = 0;

/* 设置缓冲区非空的条件变量*/
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}

/* 从缓冲区中取出整数*/
int get(struct prodcons *b)
{
int data;
pthread_mutex_lock(&b->lock);

/* 等待缓冲区非空*/
if (b->writepos == b->readpos)
{
pthread_cond_wait(&b->notempty, &b->lock);
}

/* 读数据,移动读指针*/
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos > = BUFFER_SIZE)
b->readpos = 0;

/* 设置缓冲区未满的条件变量*/
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}

/* 测试:生产者线程将1 到10000 的整数送入缓冲区,消费者线
程从缓冲区中获取整数,两者都打印信息*/

#define OVER ( – 1)
struct prodcons buffer;

void *producer(void *data)
{
int n;
for (n = 0; n < 10000; n++)
{
printf("%d —>\n", n);
put(&buffer, n);
} put(&buffer, OVER);
return NULL;
}

void *consumer(void *data)
{
int d;
while (1)
{
d = get(&buffer);
if (d == OVER)
break;
printf("—>%d \n", d);
}
return NULL;
}

int main(void)
{
pthread_t th_a, th_b;
void *retval;
init(&buffer);

/* 创建生产者和消费者线程*/
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);

/* 等待两个线程结束*/
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);

return 0;

 

from:linux社区

Ubuntu下安装Qt开发环境

一、Ubuntu下安装Qt

$ sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig qt4-demos qt4-designer

注:qt4-dev-tools 包含了Qt Assistant及Qt Linguist等工具,因此不需要单独安装这两个工具。其它的,qt4-doc 是帮助文档,包含了Qt中各个类库的详细说明以及丰富的例子程序,可以使用Qt Assistant 工具来打开阅读。qt4-qtconfig 是配置Qt环境的一个对话框,一般默认就行了,很少有必要去更改。qt4-demos 包含很多可以运行起来的可执行文件以及源代码。qt4-designer是用来设计GUI界面的设计器。
二、安装连接MySQL的驱动程序

$ sudo apt-get install libqt4-sql-mysql

三、安装第三方的QWT库

$ sudo apt-get install libqwt5-qt4 libqwt5-qt4-dev

注:安装完这些后,打开Qt Designer,就会发现左边的Widget列表里面多了”Qwt Widget”这一组;

四、安装集成开发环境QDevelop

$ sudo apt-get install qdevelop

注:不一定要安装,但就我个人感觉而言,使用Qdevelop编写代码和编译、调试,使用Qt Designer设计界面,开发效率会较高。

五、完成

from:linux社区

Ubuntu下安装开发环境

一. 安装C/C++程序的开发环境
1. sudo apt-get install build-essential //安装主要编译工具 gcc, g++, make
2. sudo apt-get install autoconf automake1.9
3. sudo apt-get install flex bison
4. sudo apt-get install manpages-dev //安装C语言函数man文档
5. sudo apt-get install binutils-doc cpp-doc gcc-doc glibc-doc stl-manual //安装相关文档

二. 安装Gnome桌面程序的开发环境
1. sudo apt-get install gnome-core-devel //安装核心文件
2. sudo apt-get install pkg-config
3. sudo apt-get install devhelp //安装GTK文档查看程序
4. sudo apt-get install libglib2.0-doc libgtk2.0-doc //安装 API参考手册及其它帮助文档
5. sudo apt-get instal glade libglade2-dev //安装GTK界面构造程序

linux下常用linux c函数

1.     进程ID为0的进程通常是调度进程,常常被称为交换进程
进程ID为1的进程通常是init进程,在自举过程结束时由内核调用
进程ID为2的进程页守护进程,负责支持虚拟存储系统的分页操作
2.     pid_t getpid( void ); 返回值:调用进程的进程ID     #i nclude <unistd.h>
3.     pid_t getppid( void ); 返回值:调用进程的父进程ID  
4.     uid_t getuid( void ); 返回值:调用进程的实际用户ID
5.     uid_t geteuid( void ); 返回值:调用进程的有效用户ID
6.     gid_t getgid( void ); 返回值:调用进程的实际组ID
7.     gid_t getegid( void ); 返回值:调用进程的有效组ID
8.     pid_t fork( void );创建子进程,返回值:子进程返回0,父进程返回子进程ID,出错-1
9.     #i nclude<sys/wait.h> pid_t wait(int *statloc);//statloc 保存进程终止状态的指针
10.     #i nclude<sys/wait.h>pid_t waitpid(pid_t pid,int *statloc,int options);
pid ==-1 等待任一子进程
pid >0 等待其子进程ID与pid相等的子进程
pid == 0 等待其组ID等于调用进程组ID的任一子进程
pid <-1 等待其组ID等于pid绝对值的任一子进程
options:
WCONTINUED 若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态
WNOHANG 若由pid指定的子进程并不是立即可用的,则waitpid阻塞,此时其返回0
WUNTRACED 若实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态
11.#i nclude<unistd.h> int setuid(uid_t uid); 设置实际实际用户ID和有效用户ID;
int setgid(gid_t gid); 设置实际组ID和有效组ID;成功返回0,错误-1
12.#i nclude<stdlib.h>int system(const char *cmdstring)
system返回值如下            
-1出现错误  
    0调用成功但是没有出现子进程  
    >0   成功退出的子进程的id

(二)线程

1. #i nclude<thread.h> int pthread_equal(pthread_t tid1, pthread_t tid2);
//相等返回非0,否则返回0
2. pthread_t pthread_self(void);返回调用线程的ID
3. int pthread_create(pthread_t *restrict tidp,
  const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg) ;
创建线程:成功返回0,否则返回错误编号
4. void pthread_exit(void *rval_ptr);//终止线程
5. int pthread_join(pthread_t thread, void **rval_ptr);
//自动线程置于分离状态,以恢复资源。成功返回0,否则返回错误编号
6. int pthread_cancel(pthread_t tid);
//请求取消同一进程中的其他线程;成功返回0,否则返回错误编号
7. void pthread_cleanup_push(void (*rtn)(void *), void *arg);
    //建立线程清理处理程序
8. void pthread_cleanup_pop(int execute);//调用建立的清理处理程序
9. int pthread_detach(pthread_t tid);//使线程进入分离状态,已分离也不出错
10.int pthread_mutex_init(pthread_mutex_t *restrict mutex,
  const pthread_nutexattr_t *restrict attr)//初始化互斥量;成功0,失败返回错误编号
11.int pthread_mutex_destroy(pthread_mutex_t *mutex);
//若有调用malloc动态分配内存则用该函数释放;成功0,失败返回错误编号
12.int pthread_mutex_lock(pthread_mutex_t *mutex);//锁住互斥量
  int pthread_mutex_trylock(pthread_mutex_t *mutex);//尝试上锁
  int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
  成功返回0,否则返回错误编号
13.int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr)//初始化读写锁
  int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//释放资源,在释放内存之前使用
成功返回0,否则返回错误编号
14.int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//在读模式下锁定读写锁
  int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//在写模式下锁定读写锁
  int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//锁住读写锁
15.int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//尝试在读模式下锁定读写锁
  int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);//尝试在写模式下锁定读写锁
成功返回0,否则返回错误编号
16.int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t * restrict attr)
//初始化条件变量
  int pthread_cond_destroy(pthread_cond_t *cond);//去除初始化条件变量
成功返回0,否则返回错误编号
17.int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
  int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,
  const struct timespec *restrict timeout);
  //等待条件变为真,如果在给定的时间内条件不能满足,那么会生成一个代表出错码的返回变量 ;成功返回0,错误返回错误编号
18.int pthread_cond_signal(pthread_cond_t *cond);//唤醒等待该条件的某个线程
  int pthread_cond_broadcast(pthread_cond_t *cond)//唤醒等待该条件的所有线程
19.int pthread_attr_init(pthread_attr_t *attr);//初始化线程属性
  int pthread_attr_destroy(pthread_attr_t *attr);//释放内存空间(动态分配时调用)
成功返回0,否则返回错误编号
20.int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr, int *detachstate);
//获取线程的分离状态
  int pthread_attr_setdetachstate(const pthread_attr_t *restrict attr, int detachstate);
  //设置分离状态 PTHREAD_CREATE_DETACHED:以分离状态启动线程
  PTHREAD_CREATE_JOINABLE:正常启动线程,应用程序可以获取线程的终止状态
    成功返回0,否则返回错误编号
21.int pthread_attr_getstack(const pthread_attr_t *restrict attr,void **restrict stackaddr, size_t *restrict stacksize);//获取线程的栈位置
int pthread_attr_setstack(const pthread_attr_t *attr, void *stackaddr, size_t *stacksize)
//设置新建线程的栈位置 ;成功返回0,否则返回错误编号

(三)消息队列

1.每个队列都有一个msqid_ds结构与之相关联:
    struct msqid_ds{
      struct ipc_perm msg_perm;
          msgqnum_t msg_qnum; //消息的数量
      msglen_t msg_qbytes; //最大消息的长度
      pid_t msg_lspid;   //最后一个发送到消息队列的进程ID
      pid_t msg_lrpid;   //最后一个读取消息的进程ID
      time_t msg_stime;   //最后一次发送到消息队列的时间
      time_t msg_rtime;   //最后一次读取消息的时间
      time_t msg_ctime; //最后一次改变的时间
      。
      。
      。
  };
  struct ipc_perm{
      uid_t uid;//拥有者有效的用户ID
      gid_t gid;//拥有者有效的组ID
      uid_t cuid;//创建者有效的用户ID
      uid_t cgid;//创建者有效的组ID
      mode_t mode; //权限
      。
      。
  }
2.#i nclude <sys/msg.h> int msgget(key_t key, int flag);
//打开一个现存的队列或创建一个新队列;成功返回0,出错返回-1
3.int msgctl(int msqid, int cmd, struct msqid_ds *buf);//对消息队列执行多种操作
cmd 可选:
IPC_STAT 取此消息队列的msqid_ds结构,并将它放在buf指向的结构
  IPC_SET:按由buf指向结构中的值,设置与此队列相关结构中的下列四个字段:msg_perm.uid,msg_perm.gid,msg_perm.mode和msg_qbytes.此命令只有下列两种进程才能执行(1)其有效用户ID等于msg_perm.cuid或msg_perm.uid;(2)具有超级用户特权的进程
  IPC_RMID:从系统中删除消息队列以及仍在该队列中的所有数据。
成功返回0,失败返回-1
4.int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag)//发送消息到消息队列中
成功返回0, 不成功返回-1并设置errno,错误码:
EACCES   对调用程序来说,调用被否定
EAGAIN   操作会阻塞进程,但(msgflg & IPC_NOWAIT) != 0
EIDRM     msqid已经从系统中删除了
EINTR     函数被信号中断
EINVAL     参数msqid无效,消息类型<1,或者msgsz越界了
flag可以指定为IPC_NOWAIT 则不会阻塞直接返回EAGAIN
注:参数msgp指向用户定义的缓冲区,他是如下的结构
struct mymsg
{
long mtypes;     消息类型
char *mtext;   消息文本
}mymsg_t
5.ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);//读取消息
成功则返回消息的数据部分的长度,出错则返回-1
type: type==0返回队列中的第一个消息
  type>0 返回队列中消息类型为type的第一个消息
  type<0返回队列中消息类型值小于或等于type绝对值的消息(多个取类型值最小的)

(四) 信号量

1. 内核为每个信号量集合设置了一个semid_ds结构:
  struct demid_ds{
    struct ipc_perm sem_perm;
    unsigned short sem_nsems; //信号量的个数
    time_t sem_otime; //上一次semop的时间
    time_t sem_ctime;//上一次change的时间
    。

};
2#i nclude<sys/sem.h>. int semget(key_t key, int nsems, int flag);//创建信号量
成功返回一个对应于信号量集标识符的非负整数,不成功返回-1并设置errno,错误码:
EACCES   存在key的信号量,但没有授予权限
EEXIST   存在key的信号量,但是
    ( (semflg & IPC_CREATE) && (semflg & IPC_EXCL) ) != 0
EINVAL   nsems <= 0或者大于系统的限制,或者nsems与信号量集的大小不符
ENOENT   不存在key的信号量,而且(semflg & IPC_CTEATE) == 0
ENOSPC   要超出系统范围内对信号量的限制了
功能:
函数返回与参数key相关的信号量集标识符。
如果键值为IPC_PRIVATE,或者semflg&IPC_CREAT非零且没有信号量集或标识符关联于key,那么函数就创建标识符及与之相关的信号量集。
参数nsems指定了集合中信号量元素的个数,可用0到nsems-1的整数来引用信号量集合中的单个信号量元素。
参数semflg指定信号量集的优先级,权限的设置与文件权限设置相同,并可以通过semclt来修改权限值,在使用信号量元素之前,应该用semctl对其进行初始化。

函数名与函数指针

一 通常的函数调用
一个通常的函数调用的例子:

//自行包含头文件
void MyFun(int x); //此处的申明也可写成:void MyFun( int );
int main(int argc, char* argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
return 0;
}
void MyFun(int x) //这里定义一个MyFun函数
{
printf(“%d\n”,x);
}

这个MyFun函数是一个无返回值的函数,它并不完成什么事情。这种调用函数的格式你应该是很熟悉的吧!看主函数中调用MyFun函数的书写格式:
MyFun(10);
我们一开始只是从功能上或者说从数学意义上理解MyFun这个函数,知道MyFun函数名代表的是一个功能(或是说一段代码)。
直到——
学习到函数指针概念时。我才不得不在思考:函数名到底又是什么东西呢?
(不要以为这是没有什么意义的事噢!呵呵,继续往下看你就知道了。)
二 函数指针变量的申明
就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
在C系列语言中,任何一个变量,总是要先申明,之后才能使用的。那么,函数指针变量也应该要先申明吧?那又是如何来申明呢?以上面的例子为例,我来申明一个可以指向MyFun函数的函数指针变量FunP。下面就是申明FunP变量的方法:
void (*FunP)(int) ; //也可写成void (*FunP)(int x);
你看,整个函数指针变量的申明格式如同函数MyFun的申明处一样,只不过——我们把MyFun改成(*FunP)而已,这样就有了一个能指向MyFun函数的指针FunP了。(当然,这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。)
三 通过函数指针变量调用函数
有了FunP指针变量后,我们就可以对它赋值指向MyFun,然后通过FunP来调用MyFun函数了。看我如何通过FunP指针变量来调用MyFun函数的:

//自行包含头文件
void MyFun(int x); //这个申明也可写成:void MyFun( int );
void (*FunP)(int ); //也可申明成void(*FunP)(int x),但习惯上一般不这样。
int main(int argc, char* argv[])
{
MyFun(10); //这是直接调用MyFun函数
FunP=&MyFun; //将MyFun函数的地址赋给FunP变量
(*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的。
}
void MyFun(int x) //这里定义一个MyFun函数
{
printf(“%d\n”,x);
}

请看黑体字部分的代码及注释。
运行看看。嗯,不错,程序运行得很好。
哦,我的感觉是:MyFun与FunP的类型关系类似于int 与int *的关系。函数MyFun好像是一个如int的变量(或常量),而FunP则像一个如int *一样的指针变量。
int i,*pi;
pi=&i; //与FunP=&MyFun比较。
(你的感觉呢?)
呵呵,其实不然——
四 调用函数的其它书写格式
函数指针也可如下使用,来完成同样的事情:

//自行包含头文件
void MyFun(int x);
void (*FunP)(int ); //申明一个用以指向同样参数,返回值函数的指针变量。
int main(int argc, char* argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=MyFun; //将MyFun函数的地址赋给FunP变量
FunP(20); //这是通过函数指针变量来调用MyFun函数的。
return 0;
}
void MyFun(int x) //这里定义一个MyFun函数
{
printf(“%d\n”,x);
}

我改了黑体字部分(请自行与之前的代码比较一下)。
运行试试,啊!一样地成功。
咦?
FunP=MyFun;
可以这样将MyFun值同赋值给FunP,难道MyFun与FunP是同一数据类型(即如同的int 与int的关系),而不是如同int 与int*的关系了?(有没有一点点的糊涂了?)
看来与之前的代码有点矛盾了,是吧!所以我说嘛!
请容许我暂不给你解释,继续看以下几种情况(这些可都是可以正确运行的代码哟!):
代码之三:

int main(int argc, char* argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=&MyFun; //将MyFun函数的地址赋给FunP变量
FunP(20); //这是通过函数指针变量来调用MyFun函数的。
return 0;
}

代码之四:
int main(int argc, char* argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=MyFun; //将MyFun函数的地址赋给FunP变量
(*FunP)(20); //这是通过函数指针变量来调用MyFun函数的。
return 0;
}

真的是可以这样的噢!
(哇!真是要晕倒了!)
还有呐!看——
int main(int argc, char* argv[])
{
(*MyFun)(10); //看,函数名MyFun也可以有这样的调用格式
return 0;
}

你也许第一次见到吧:函数名调用也可以是这样写的啊!(只不过我们平常没有这样书写罢了。)
那么,这些又说明了什么呢?
呵呵!依据以往的知识和经验来推理本篇的“新发现”,我想就连“福尔摩斯”也必定会由此分析并推断出以下的结论:
1. 其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。
2. 但函数名调用如果都得如(*MyFun)(10);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许MyFun(10);这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。
3. 为统一起见,FunP函数指针变量也可以FunP(10)的形式来调用。
4. 赋值时,即可FunP=&MyFun形式,也可FunP=MyFun。
上述代码的写法,随便你爱怎么着!
请这样理解吧!这可是有助于你对函数指针的应用喽!
最后——
补充说明一点:在函数的申明处:
void MyFun(int ); //不能写成void (*MyFun)(int )。
void (*FunP)(int ); //不能写成void FunP(int )。

(请看注释)这一点是要注意的。
五 定义某一函数的指针类型:
就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。
我先给你一个自定义数据类型的例子。
typedef int* PINT; //为int* 类型定义了一个PINT的别名
int main()
{
int x;
PINT px=&x; //与int * px=&x;是等价的。PINT类型其实就是int * 类型
*px=10; //px就是int*类型的变量
return 0;
}
根据注释,应该不难看懂吧!(虽然你可能很少这样定义使用,但以后学习Win32编程时会经常见到的。)
下面我们来看一下函数指针类型的定义及使用:(请与上对照!)
//自行包含头文件
void MyFun(int x); //此处的申明也可写成:void MyFun( int );
typedef void (*FunType)(int ); //这样只是定义一个函数指针类型
FunType FunP; //然后用FunType类型来申明全局FunP变量
int main(int argc, char* argv[])
{
//FunType FunP; //函数指针变量当然也是可以是局部的 ,那就请在这里申明了。
MyFun(10);
FunP=&MyFun;
(*FunP)(20);
return 0;
}
void MyFun(int x)
{
printf(“%d\n”,x);
}

看黑体部分:
首先,在void (*FunType)(int ); 前加了一个typedef 。这样只是定义一个名为FunType函数指针类型,而不是一个FunType变量。
然后,FunType FunP; 这句就如PINT px;一样地申明一个FunP变量。
其它相同。整个程序完成了相同的事。
这样做法的好处是:
有了FunType类型后,我们就可以同样地、很方便地用FunType类型来申明多个同类型的函数指针变量了。如下:
FunType FunP2;
FunType FunP3;
//……
六 函数指针作为某个函数的参数
既然函数指针变量是一个变量,当然也可以作为某个函数的参数来使用的。所以,你还应知道函数指针是如何作为某个函数的参数来传递使用的。
给你一个实例:
要求:我要设计一个CallMyFun函数,这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数(注:这三个函数的定义格式应相同)。
实现:代码如下:
//自行包含头文件
void MyFun1(int x);
void MyFun2(int x);
void MyFun3(int x);
typedef void (*FunType)(int ); //②. 定义一个函数指针类型FunType,与①函数类型一至
void CallMyFun(FunType fp,int x);
int main(int argc, char* argv[])
{
CallMyFun(MyFun1,10); //⑤. 通过CallMyFun函数分别调用三个不同的函数
CallMyFun(MyFun2,20);
CallMyFun(MyFun3,30);
}
void CallMyFun(FunType fp,int x) //③. 参数fp的类型是FunType。
{
fp(x);//④. 通过fp的指针执行传递进来的函数,注意fp所指的函数是有一个参数的
}
void MyFun1(int x) // ①. 这是个有一个参数的函数,以下两个函数也相同
{
printf(“函数MyFun1中输出:%d\n”,x);
}
void MyFun2(int x)
{
printf(“函数MyFun2中输出:%d\n”,x);
}
void MyFun3(int x)
{
printf(“函数MyFun3中输出:%d\n”,x);
}

经典百度面试算法:万人工厂分配任务

: A厂有1万个工人,编号0-9999,( EE[10000] ), 1个厂长( GG )分派任务, 1个监工( MM )管理工人.厂子忙的时间不确定,可能突然很忙,1天接到任务5000多个,1个任务只能分配给1个工人做, 也可能好几十天没新任务.厂长分配任务给这1万个工人干,按工人编号一个一个来,到最后一个工人就又从头开始,任务完成时间各不相同,可能一个工人在分配任务的时候手里还有任务, 就得换下一个。

但是这1万个工人都很懒,领到了任务先不做,需要监工1个1个去问,如果工人有任务,就做,如果工人没任务,则不做。厂长只管分任务,1个1个来,可能几天也没新任务,不累;但是监工很累,监工每天都要看所有工人的情况,即使这些工人都没有任务, 实际上每天工人(80%左右)是没任务的,请问,怎么让监工的工作轻松下来. 比如说每天只问1小半工人.

Peak Wong:

分析如下:

因为“任务完成时间各不相同” ,所以有可能a,b,c某天都有任务,但b的任务最先完成,那么当b的任务完成后,有任务的人的工号可能是不连续的;

用一个数组表示1万个工人是否有任务,并保存最后被分配任务的人的工号;

1)从前一天“最后被分配任务的人的工号”开始,依次问下一个工号的人,置对应的工作状态,直到碰到前一天无工作,且当天也无工作的人;并更新当步最后有工作的人的工号为当天的“最后被分配任务的人的工号”;

2)从前一天“最后被分配任务的人的工号”开始,依次问上一个工号且前一天有工作的人;

问题是监工可以知道那些信息,否则还不是一个一个接着去问。

还有就是tailzhou的步骤1消耗的时间T1, 工人完成的时间T2,如果T2

所以很多条件都没有限制。

from:http://www.coder4.com/archives/488

国内避孕套销售商纷纷表示绝望…

knctt3xb

Ubuntu 10.04 gcc g++ 4.4降级到4.3

我依照以下方法,却得到ln: creating hard link `gcc’ => `/usr/bin/gcc-4.3′: Invalid cross-device link 请问是什么回事呢?

将gcc-4.4降级成gcc-4.3 具体操作: sudo apt-get install gcc-4.3(安装gcc-4.3) sudo apt-get install g++-4.3(安装g++-4.3)sudo apt-get install g++-4.3-multilib (安装g++-4.3-multilib) 安装完4.3版本后,执行gcc –version后会发现版本仍然是4.4,因为gcc已经和4.4版本进行了链接,因此需要对gcc重新进行链接 具体操作: sudo ln -f /usr/bin/gcc-4.3 gcc sudo ln -f/usr/bin/g++-4.3 g++ 这样就可以用4.3版本的gcc和g++将原来的覆盖掉,重新进入android源码目录执行make就可以正常编译
【或者可以安转gcc依赖包 apt-get install build-essential】
请大家帮帮忙

文章标题 : Re: Ubuntu10.04 gcc g++4.4降级4.3的问题

在我的系统上
ls -l /usr/bin/gcc
lrwxrwxrwx 1 root root 7 2009-11-10 20:40 /usr/bin/gcc -> gcc-4.4
意思是/usr/bin/gcc是/usr/bin/gcc-4.4的 soft link,不是hard link,目前我常用的都是soft link,用法是ln -s file1 file2,然后ls -l file2查看。
你的情况应该是
cd /usr/bin
sudo ln -sf cpp-4.3 cpp
sudo ln -sf gcc-4.3 gcc
sudo ln -sf g++-4.3 g++
hard link据说不支持在不同分区之间连接文件(你的/home和/在不同分区?),soft link支持。
你的命令sudo ln -f /usr/bin/gcc-4.3 gcc似乎是把/usr/bin/gcc做个hard link到当前目录下的文件gcc。
另外系统默认版本的gcc最好不要改,要改也得是同一版本,比如gcc 4.3.0改为gcc 4.3.2或gcc 4.4.0到gcc 4.4.4。从gcc 4.4改到gcc 4.3是有风险的。
有个办法使用非系统默认版本的gcc,就是自己编译gcc并安装到/opt/gcc目录下去,不用多少时间,15分钟就够了(Intel E2140,1GB RAM)。
如果你熟悉gcc的编译,这段不用看。编译前把gcc-4.3的包全部卸掉,并把gcc,cpp,g++这几个提供soft link到gcc-4.4的包重新装一遍。
安装编译gcc的依赖包gmp,mpfr,cloog-ppl,mpc,libelf,注意都要带devel或dev字样的包。
http://gcc.cybermirror.org/releases/gcc-4.3.4/
下载源码
gcc- core*.tar.bz2是c编译器
gcc-fortran*.tar.bz2是fortran编译器
gcc- g++*.tar.bz2是g++编译器
gcc-objc*.tar.bz2是objective c编译器
一般人用到的就c,c++ 而已
mkdir ~/build
下载到home下的build目录

http://gcc.cybermirror.org/releases/gcc-4.3.4/gcc-core-4.3.4.tar.bz2

http://gcc.cybermirror.org/releases/gcc-4.3.4/gcc-g++-4.3.4.tar.bz2

cd ~/build
tar jxf gcc-core-4.3.4.tar.bz2
tar jxf gcc-g++-4.3.4.tar.bz2
cd gcc-4.3.4
mkdir build
然后
gcc -v 2> build-config.txt
打开build-config.txt
开 始修改
比如我的是

代码:
Using built-in specs.
Target: i586-SUSE-linux
Configured with: ../configure –prefix=/usr –infodir=/usr/share/info –mandir=/usr/share/man –libdir=/usr/lib –libexecdir=/usr/lib –enable-languages=c,c++,objc,fortran,obj-c++ –enable-checking=release –with-gxx-include-dir=/usr/include/c++/4.4 –enable-ssp –disable-libssp –with-bugurl=http://bugs.openSUSE.org/ –with-pkgversion=’SUSE Linux’ –disable-libgcj –disable-libmudflap –with-slibdir=/lib –with-system-zlib –enable-__cxa_atexit –enable-libstdcxx-allocator=new –disable-libstdcxx-pch –enable-version-specific-runtime-libs –program-suffix=-4.4 –enable-linux-futex –without-system-libunwind –with-arch-32=i586 –with-tune=generic –build=i586-suse-linux
Thread model: posix
gcc version 4.4.4 (SUSE Linux)

改成

代 码:
../configure \
–prefix=/opt/gcc \
–enable-languages=c,c++ \
–enable-checking=release \
–enable-ssp \
–disable-libssp \
–with-bugurl=http://bugs.openSUSE.org/ \
–with-pkgversion=’SUSE Linux’ \
–disable-libgcj –disable-libmudflap \
–with-system-zlib \
–enable-__cxa_atexit \
–enable-libstdcxx-allocator=new \
–disable-libstdcxx-pch \
–enable-version-specific-runtime-libs \
–program-suffix=-4.4 \
–enable-linux-futex \
–without-system-libunwind \
–with-arch-32=i586 \
–with-tune=generic \
–build=i586-SUSE-linux \
–disable-bootstrap

也就是把头尾不要,提到/usr和/lib目录的行全不要,–program-suffix那行也不要,分行,再加一行–disable-bootstrap。我的这段

代码:
../configure

仅 供参考,具体还是要你自己改你自己的build-config.txt
现在已经在~/build/gcc-4.3.4/build目录了
把 改好的build-config.txt的内容复制下来并运行,我的是

代码:
../configure \
–prefix=/opt/gcc \
–enable-languages=c,c++ \
–enable-checking=release \
–enable-ssp \
–disable-libssp \
–with-bugurl=http://bugs.openSUSE.org/ \
–with-pkgversion=’SUSE Linux’ \
–disable-libgcj –disable-libmudflap \
–with-system-zlib \
–enable-__cxa_atexit \
–enable-libstdcxx-allocator=new \
–disable-libstdcxx-pch \
–enable-version-specific-runtime-libs \
–enable-linux-futex \
–without-system-libunwind \
–with-arch-32=i586 \
–with-tune=generic \
–build=i586-SUSE-linux \
–disable-bootstrap

然后
make -jN,cpu有几个核N就填几
最后
sudo make install
可选步骤
cd /opt/gcc/libexec/gcc/*/*
sudo strip -sv cc1*

最后写个脚本gcc43-env.sh放到~/bin目录,内容如下

代码:
#!/bin/sh
export PATH=/opt/gcc/bin:$PATH

你要使用gcc-4.3只用
source gcc43-env.sh
就行了。

from:ubuntu社区