分类目录归档:C/C++

Zephir用类似PHP的语法写PHP C扩展

Zephir是一个非常有意思的项目。它是专门针对编写PHP C扩展而创建的,是PHP C框架Phalcon的实现语言。Zephir提供了类似PHP的语法,然后转换成PHP C扩展代码,然后就是正常的C扩展编译和安装。

官网:http://zephir-lang.com/

Zephir依赖re2c来进行语法分析(PHP本身也使用re2c来进行语法分析),需要把Zephir代码转换为PHP C扩展的C代码,所以依赖PHP的头文件,然后需要编译,那么就必须有编译器(gcc):(https://docs.zephir-lang.com/en/latest/install.html)

# 安装PHP的头文件,如果是RPM安装,需要安装devel包
php70w-devel-7.0.13-1.w7.x86_64

# 安装re2c:http://re2c.org/
yum install re2c

# 安装编译器
yum install gcc make autoconf git

#安装
git clone https://github.com/phalcon/zephir
cd zehpir
./install -c   #拷贝zephir/bin/zephir 到  /usr/local/bin/zephir

zephir help

编译实例:

git clone --depth=1 https://github.com/phalcongelist/beanspeak.git
cd beanspeak
zephir build
# Or, for PHP 7 use
zephir build --backend=ZendEngine3

参考例子:

#https://github.com/phalcongelist/beanspeak/blob/master/beanspeak/client.zep
namespace Beanspeak;

/**
 * Beanspeak\Client
 *
 * Class to access the beanstalk queue service.
 *
 * Implements the beanstalk protocol spec 1.10.
 *
 * <code>
 * use Beanspeak\Client;
 *
 * // Each connection parameter is optional
 * $queue = new Client([
 *     'host'       => '127.0.0.1', // The beanstalk server hostname or IP address to connect to
 *     'port'       => 11300,       // The port of the server to connect to
 *     'timeout'    => 60,          // Timeout in seconds when establishing the connection
 *     'persistent' => true,        // Whether to make the connection persistent or not
 *     'wretries'   => 8,           // Write retries
 * ]);
 * </code>
 *
 * @link https://github.com/kr/beanstalkd/
 */
class Client
{
	/**
	 * The current socket connection.
	 * @var resource
	 */
	protected socket;

	/**
	 * The current connection options.
	 * @var array
	 */
	protected options = [];

	/**
	 * The current used tube.
	 * @var string
	 */
	protected usedTube = "default";

	/**
	 * The current watched tubes.
	 * @var array
	 */
	protected watchedTubes = [ "default" : true ];

	/**
	 * Beanspeak\Client constructor
	 */
	public function __construct(array options = null)
	{
		array defaults = [
			"host"       : "127.0.0.1",
			"port"       : "11300",
			"persistent" : true,
			"timeout"    : "60",
			"wretries"   : 8
		];

		if typeof options != "array" {
			let this->{"options"} = defaults;
		} else {
			let this->{"options"} = options + defaults;
		}
	}

	/**
	 * Makes a connection to the Beanstalk server.
	 *
	 * The resulting stream will not have any timeout set on it.
	 * Which means it can wait an unlimited amount of time until a packet
	 * becomes available.
	 *
	 * @throws Exception
	 */
	public function connect() -> resource
	{
		var e, options, socket, usedTube, tube;

		if this->isConnected() {
			this->disconnect();
		}

		let options = this->options;

		try {
			if options["persistent"] {
				let socket = pfsockopen(options["host"], options["port"], null, null, options["timeout"]);
			} else {
				let socket = fsockopen(options["host"], options["port"], null, null, options["timeout"]);
			}

			if typeof socket != "resource" {
				throw new Exception("Can't connect to Beanstalk server.");
			}
		} catch  \Exception, e {
			throw new Exception(e->getMessage());
		}

		stream_set_timeout(socket, -1, null);

		let this->{"socket"} = socket,
			usedTube = this->usedTube;

		if usedTube != "default" {
			this->useTube(usedTube);
		}

		for tube, _ in this->watchedTubes {
			if tube != "default" {
				unset(this->watchedTubes[tube]);
				this->watch(tube);
			}
		}

		if !isset this->watchedTubes["default"] {
			this->ignore("default");
		}

		return socket;
	}

	/**
	 * Closes the connection to the Beanstalk server.
	 *
	 * Will throw an exception if closing the connection fails, to allow
	 * handling the then undefined state.
	 *
	 * @throws Exception
	 */
	public function disconnect() -> boolean
	{
		var socket, status;

		if !this->isConnected() {
			return false;
		}

		let socket = this->socket,
			status = fclose(socket);

		if !status {
			throw new Exception("Failed to close connection.");
		}

		let this->{"socket"}       = null,
			this->{"usedTube"}     = "default",
			this->{"watchedTubes"} = [ "default" : true ];

		return true;
	}

	/**
	 * Whether the connection is established or not.
	 */
	public function isConnected() -> boolean
	{
		return typeof this->socket == "resource";
	}

	/**
	 * Inserts a job into the client's currently used tube.
	 *
	 * <code>
	 * $task = [
	 *     'recipient' => 'user@mail.com',
	 *     'subject'   => 'Welcome',
	 *     'content'   => $content,
	 * ];
	 *
	 * $put = $queue->pit($task, 999, 60 * 60, 3600);
	 * </code>
	 */
	public function put(var data, int priority = 1024, int delay = 0, int ttr = 86400) -> int|boolean
	{
		var status, response, serialized, length;

		// Data is automatically serialized before be sent to the server
		let serialized = serialize(data),
			length     = strlen(serialized);

		this->write("put " . priority . " " . delay . " " . ttr . " " . length . "\r\n" . serialized);

		let response = this->readStatus();

		if isset response[1] {
			let status = response[0];

			if status == "INSERTED" || status == "BURIED" {
				return intval(response[1]);
			}
		}

		return false;
	}

	/**
	 * Inserts a job into the desired tube.
	 *
	 * <code>
	 * $task = [
	 *     'recipient' => 'user@mail.com',
	 *     'subject'   => 'Welcome',
	 *     'content'   => $content,
	 * ];
	 *
	 * $queue->putInTube('tube-name', $task, 999, 60 * 60, 3600);
	 * </code>
	 */
	public function putInTube(string! tube, var data, int priority = 1024, int delay = 0, int ttr = 86400) -> boolean|int
	{
		var  response;

		let response = this->useTube(tube);
		if typeof response == "object" {
			return this->put(data, priority, delay, ttr);
		}

		return false;
	}

	/**
	 * Change the active tube.
	 *
	 * The "use" command is for producers. Subsequent put commands will put jobs
	 * into the tube specified by this command. If no use command has been issued,
	 * jobs will be put into the tube named "default".
	 *
	 * <code>
	 * $queue->useTube('mail-queue');
	 * </code>
	 *
	 * @throws Exception
	 */
	public function useTube(string! tube) -> <Client>
	{
		var response, status, used;

		let used = this->usedTube;
		if used == tube {
			return this;
		}

		this->write("use " . tube);

		let response = this->readStatus();

		if isset response[1] && response[0] == "USING" {
			let status = response[0];

			if status == "USING" {
				let this->{"usedTube"} = tube;
				return this;
			}
		}

		throw new Exception(
			"Unable to change the active tube. Server response: ". join(" ", response)
		);
	}

	/**
	 * Lets the client inspect a job in the system.
	 *
	 * <code>
	 * $peekJob = $queue->peek($jobId);
	 * </code>
	 */
	public function peekJob(int id) -> boolean|<Job>
	{
		var response;

		this->write("peek " . id);

		let response = this->readStatus();
		if isset response[2] && response[0] == "FOUND" {
			return new Job(this, response[1], unserialize(this->read(response[2])));
		}

		return false;
	}

	/**
	 * Return the delayed job with the shortest delay left.
	 *
	 * <code>
	 * $queue->peekDelayed();
	 * </code>
	 */
	public function peekDelayed() -> boolean|<Job>
	{
		var response;

		this->write("peek-delayed");

		let response = this->readStatus();
		if isset response[2] && response[0] == "FOUND" {
			return new Job(this, response[1], unserialize(this->read(response[2])));
		}

		return false;
	}

	/**
	 * Return the next job in the list of buried jobs.
	 *
	 * <code>
	 * $queue->peekBuried();
	 * </code>
	 */
	public function peekBuried() -> boolean|<Job>
	{
		var response;

		this->write("peek-buried");

		let response = this->readStatus();
		if isset response[2] && response[0] == "FOUND" {
			return new Job(this, response[1], unserialize(this->read(response[2])));
		}

		return false;
	}

	/**
	 * Inspect the next ready job.
	 *
	 * <code>
	 * $queue->peekReady();
	 * </code>
	 */
	public function peekReady() -> boolean|<Job>
	{
		var response;

		this->write("peek-ready");

		let response = this->readStatus();
		if isset response[2] && response[0] == "FOUND" {
			return new Job(this, response[1], unserialize(this->read(response[2])));
		}

		return false;
	}

	/**
	 * Moves jobs into the ready queue.
	 * The Kick command applies only to the currently used tube.
	 *
	 * <code>
	 * $queue->kick(3);
	 * </code>
	 */
	public function kick(int bound) -> boolean|int
	{
		var response;

		this->write("kick " . bound);

		let response = this->readStatus();
		if isset response[1] && response[0] == "KICKED" {
			return intval(response[1]);
		}

		return false;
	}

	/**
	 * Adds the named tube to the watch list, to reserve jobs from.
	 *
	 * <code>
	 * $count = $queue->watch($tube);
	 * </code>
	 *
	 * @throws Exception
	 */
	public function watch(string! tube) -> <Client>
	{
		var response, watchedTubes;

		let watchedTubes = this->watchedTubes;
		if !isset watchedTubes[tube] {
			this->write("watch " . tube);

			let response = this->readStatus();
			if !isset response[1] || response[0] != "WATCHING" {
				throw new Exception("Unhandled response: " . join(" ", response));
			}

			let this->watchedTubes[tube] = true;
		}

		return this;
	}

	/**
	* Adds the named tube to the watch list, to reserve jobs from, and
	* ignores any other tubes remaining on the watchlist.
	*
	* <code>
	* $count = $queue->watchOnly($tube);
	* </code>
	*
	* @throws Exception
	*/
	public function watchOnly(string! tube) -> <Client>
	{
		var watchedTubes, watchedTube;

		this->watch(tube);

		let watchedTubes = this->watchedTubes;
		for watchedTube, _ in watchedTubes {
			if watchedTube == tube {
				continue;
			}

			this->ignore(watchedTube);
		}

		return this;
	}

	/**
	 * Reserves/locks a ready job from the specified tube.
	 *
	 * <code>
	 * $job = $queue->reserve();
	 * </code>
	 *
	 * @throws Exception
	 */
	public function reserve(int timeout = -1) -> boolean|<Job>
	{
		var response;
		string command;

		if timeout >= 0 {
			let command = "reserve-with-timeout " . timeout;
		} else {
			let command = "reserve";
		}

		this->write(command);

		let response = this->readStatus();

		if response[0] != "RESERVED" || !isset response[2] {
			return false;
		}

		return new Job(this, response[1], unserialize(this->read(response[2])));
	}

	/**
	 * Reserves/locks a ready job from the specified tube.
	 *
	 * <code>
	 * $job = $queue->reserve();
	 * </code>
	 *
	 * @throws Exception
	 */
	public function reserveFromTube(string tube, int timeout = -1) -> boolean|<Job>
	{
		this->watch(tube);

		return this->reserve(timeout);
	}

	/**
	 * Removes the named tube from the watch list for the current connection.
	 *
	 * <code>
	 * $count = $queue->ignore('tube-name);
	 * </code>
	 *
	 * @throws Exception
	 */
	public function ignore(string! tube) -> <Client>
	{
		var response, watchedTubes;

		let watchedTubes = this->watchedTubes;
		if typeof watchedTubes != "array" {
			return this;
		}

		if isset watchedTubes[tube] {
			this->write("ignore " . tube);

			let response = this->readStatus();
			if response[0] == "NOT_IGNORED" {
				throw new Exception("Cannot ignore last tube in watchlist.");
			}

			if !isset response[1] || response[0] != "WATCHING" {
				throw new Exception("Unhandled response: " . join(" ", response));
			}

			unset(watchedTubes[tube]);
			let this->watchedTubes = watchedTubes;
		}

		return this;
	}

	/**
	 * Gives statistical information about the system as a whole.
	 *
	 * <code>
	 * $queue->stats();
	 * </code>
	 */
	public function stats() -> boolean|array
	{
		var response;

		this->write("stats");

		let response = this->readYaml();
		if response[0] != "OK" {
			return false;
		}

		return response[2];
	}

	/**
	 * Gives statistical information about the specified tube if it exists.
	 *
	 * <code>
	 * $stats = $queue->statsTube('process-bitcoin');
	 * </code>
	 */
	public function statsTube(string! tube) -> boolean|array
	{
		var response;

		this->write("stats-tube " . tube);

		let response = this->readYaml();
		if response[0] != "OK" {
			return false;
		}

		return response[2];
	}

	/**
	 * Returns a list of all existing tubes.
	 *
	 * <code>
	 * $tubes = $queue->listTubes();
	 * </code>
	 */
	public function listTubes() -> boolean|array
	{
		var response;

		this->write("list-tubes");

		let response = this->readYaml();
		if response[0] != "OK" {
			return false;
		}

		return response[2];
	}

	/**
	 * Returns the tube currently being used by the client.
	 *
	 * <code>
	 * $tube = $queue->listTubeUsed(); // local cache
	 * $tube = $queue->listTubeUsed(); // ask server
	 * </code>
	 *
	 * @throws Exception
	 */
	public function listTubeUsed(boolean ask = false) -> string
	{
		var response;

		if !ask {
			return this->usedTube;
		}

		this->write("list-tube-used");

		let response = this->readStatus();

		if isset response[1] && response[0] == "USING" {
			let this->{"usedTube"} = response[1];
			return response[1];
		}

		throw new Exception("Unhandled response form beanstalkd server: " . join(" ", response));
	}

	/**
	 * Returns a list tubes currently being watched by the client.
	 *
	 * <code>
	 * $tubes = $queue->listTubesWatched(); // local cache
	 * $tubes = $queue->listTubesWatched(true); // ask server
	 * </code>
	 *
	 * @throws Exception
	 */
	public function listTubesWatched(boolean ask = false) -> array
	{
		var response;

		if !ask {
			return array_keys(this->watchedTubes);
		}

		this->write("list-tubes-watched");

		let response = this->readYaml();
		if response[0] != "OK" {
			throw new Exception("Unhandled response form beanstalkd server: " . join(" ", response));
		}

		let this->{"watchedTubes"} = array_fill_keys(response[2], true);

		return this->watchedTubes;
	}

	/**
	 * Can delay any new job being reserved for a given time.
	 *
	 * <code>
	 * $queue->pauseTube('process-video', 60 * 60);
	 * </code>
	 */
	public function pauseTube(string! tube, int delay) -> boolean
	{
		var response;

		this->write("pause-tube " . tube . " " . delay);

		let response = this->readStatus();
		if !isset response[0] || response[0] != "PAUSED" {
			return false;
		}

		return true;
	}

	/**
	 * Resume the tube.
	 *
	 * <code>
	 * $queue->resumeTube('process-video');
	 * </code>
	 */
	public function resumeTube(string! tube) -> boolean
	{
		return this->pauseTube(tube, 0);
	}

	/**
	 * Simply closes the connection.
	 *
	 * <code>
	 * $queue->quit();
	 * </code>
	 */
	public function quit() -> boolean
	{
		this->write("quit");
		this->disconnect();

		return typeof this->socket != "resource";
	}

	/**
	 * Writes data to the socket.
	 * Performs a connection if none is available.
	 * @throws Exception
	 */
	public function write(string data) -> int
	{
		var socket, retries, written, step, length;

		if !this->isConnected() {
			this->connect();

			if !this->isConnected() {
				throw new Exception("Unable to establish connection with beanstalkd server.");
			}
		}

		let retries = this->options["wretries"],
			socket  = this->socket,
			data   .= "\r\n",
			step    = 0,
			written = 0;

		let length = strlen(data);

		while written < length {
			let step++;

			if step >= retries && !written {
				throw new Exception("Failed to write data to socket after " . retries . " tries.");
			}

			let written += fwrite(socket, substr(data, written));
		}

		return written;
	}

	/**
	 * Reads a packet from the socket.
	 * Performs a connection if none is available.
	 * @throws Exception
	 */
	public function read(int length = 0) -> boolean|string
	{
		var socket, data, meta;

		if !this->isConnected() {
			this->connect();

			if !this->isConnected() {
				return false;
			}
		}

		let socket = this->socket;

		if length {
			if feof(socket) {
				throw new Exception("Failed to read data from socket (EOF).");
			}

			let data = stream_get_line(socket, length + 2),
				meta = stream_get_meta_data(socket);

			if meta["timed_out"] {
				throw new Exception("Connection timed out upon attempt to read data from socket.");
			}

			if false === data {
				throw new Exception("Failed to read data from socket.");
			}

			let data = rtrim(data, "\r\n");
		} else {
			let data = stream_get_line(socket, 16384, "\r\n");
		}

		array errors = [
			"UNKNOWN_COMMAND" : "Unnown command.",
			"JOB_TOO_BIG"     : "Job data exceeds server-enforced limit.",
			"BAD_FORMAT"      : "Bad command format.",
			"OUT_OF_MEMORY"   : "Out of memory."
		];

		if isset errors[data] {
			throw new Exception(errors[data]);
		}

		return data;
	}

	/**
	 * Fetch a YAML payload from the Beanstalkd server.
	 */
	final public function readYaml() -> array
	{
		var response, status, data = [], bytes = 0;

		let response = this->readStatus();

		if isset response[0] {
			let status = response[0];
		} else {
			let status = "UNKNOWN";
		}

		if isset response[1] {
			let bytes = response[1],
				data  = this->yamlParse();
		}

		return [
			status,
			bytes,
			data
		];
	}

	/**
	 * Reads the latest status from the Beanstalkd server.
	 */
	final public function readStatus() -> array
	{
		var status;
		let status = this->read();
		if false === status {
			return [];
		}

		return explode(" ", status);
	}

	private function yamlParse() -> array
	{
		var data, lines, key, value, values, tmp, response = [];

		let data = this->read();

		if typeof data != "string" || empty(data) {
			return [];
		}

		if function_exists("yaml_parse") {
			let response = yaml_parse(data);

			return response;
		}

		let data  = rtrim(data),
			lines = preg_split("#[\r\n]+#", rtrim(data));

		if isset lines[0] && lines[0] == "---" {
			array_shift(lines);
		}

		if typeof lines != "array" || empty(lines) {
			trigger_error("YAML parse error.", E_USER_WARNING);
			return [];
		}

		for key, value in lines {
			if starts_with(value, "-") {
				let value = ltrim(value, "- ");
			} elseif strpos(value, ":") !== false {
				let values = explode(":", value);

				if !isset values[1] {
					trigger_error("YAML parse error for line: \"" . value . "\"", E_USER_WARNING);
				} else {
					let key   = values[0],
						value = ltrim(values[1], " ");
				}
			}

			if is_numeric(value) {
				let tmp = intval(value);

				if tmp == value {
					let value = tmp;
				} else {
					let value = doubleval(value);
				}
			}

			let response[key] = value;
		}

		return response;
	}
}

Linux下C程序编译 与 调试(GCC 和 GDB)

Linux下C程序编译

GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,在CentOS下如果没有安装可以:

#安装gcc
yum install gcc
Package gcc-4.4.7-4.el6.x86_64 already installed and latest version
Nothing to do
#查看安装的文件
rpm -ql gcc
/usr/bin/c89
/usr/bin/c99
/usr/bin/cc
/usr/bin/gcc
...
#查看cc文件
ls -lah /usr/bin/cc
lrwxrwxrwx 1 root root 3 May 20 06:24 /usr/bin/cc -> gcc

c89 和 c99针对C语言的两个标准。cc是gcc的链接。所以,使用cc就是使用gcc。

查看gcc的版本信息:

gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)

用法:

gcc [options] file...

options为编译选项,GCC总共提供的编译选项超过100个,但只少数几个会被频繁使用,直接使用gcc加源文件它会为目标程序生成默认的文件名a.out,可用-o编译选项来为将产生的可执行文件制定一个文件名来代替a.out。

-o <file>   Place the output into <file>(链接生成可执行文件)
-c          Compile and assemble, but do not link(生成目标文件,一般是点o结尾,不链接)
-S          Compile only; do not assemble or link
-E          Preprocess only; do not compile, assemble or link(只做预处理,预处理输出被送到标准输出)
-O	    对源代码进行基本优化从而使得程序执行更快。-O2产生尽可能小和尽可能快的代码。
-g	    告诉GCC产生能被GNU调试器使用的调试信息以调试程序,在GCC里,可以联用-g和-O(产生优化代码)

一般例子:

vi vfeelit.c
#include <stdio.h>
int main(void)
{
	printf("Welcome!");
	return 0;
}

gcc -c vfeelit.c  		#编译 产生vfeelit.o
gcc -o vfeelit vfeelit.o	#链接 从目标文件生成vfeelit这个可执行文件

##也可以从源文件直接生成可执行文件
gcc -o vfeelit vfeelit.c	#直接编译链接

Linux下C程序调试
安装GDB调试器

yum install gdb
Package gdb-7.2-60.el6_4.1.x86_64 already installed and latest version
Nothing to do

可能遇到问题,参考:http://blog.ifeeline.com/1079.html

GDB是一个用来调试C和C++程序的调试器,可以进行设置断点、观察变量、单步等一系列调试工作,常用命令:

file	装入要调试的可执行文件
kill	终止正在调试的程序
list	列表显示源代码
next	执行一行源代码但不进入函数内部
step	执行一行源代码而且进入函数内部
run	执行当前被调试的程序
quit	终止GDB
watch	监视一个变量值
break 	在代码里设置断点,程序执行到这里时挂起
make	不退出GDB重新产生可执行文件
shell	不离开GDB执行shell

演示程序:(求0+1+2+3+…+99)

vi sum.c
#include <stdio.h>

int main(void)
{
	int sum=0,i;
	for(i=0;i<100;i++){
		sum += i;
	}
	printf("The sum 0+1+2+3+...+99 is %d",sum);
	return 0;
}

#执行如下命令编译sum.c(加-g选项产生debug信息):
gcc -g -o sum sum.c

#在命令行上键入gdb sum开始调试sum,然后运行run命名执行sum
gdb sum
...
Reading symbols from /root/sum...done.
(gdb) run
Starting program: /root/sum 
The sum 0+1+2+3+...+99 is 4950
Program exited normally.
(gdb)

#list命令用于列出源代码,对上述程序两次运行list
(gdb) list
1	#include <stdio.h>
2	
3	int main(void)
4	{
5		int sum=0,i;
6		for(i=0;i<100;i++){
7			sum += i;
8		}
9		printf("The sum 0+1+2+3+...+99 is %d",sum);
10		return 0;
(gdb) list
11	}

#根据列出的源程序,如要将断点设置在第5行,再次运行run命令,程序将停留在第5行
#设置断点的另一种语法是break <function>,它在进入指定函数时停住。
(gdb) break 5
Breakpoint 1 at 0x4004cc: file sum.c, line 5.
(gdb) run
Starting program: /root/sum 

Breakpoint 1, main () at sum.c:5
5		int sum=0,i;

#clear用于清除所有已定义的断点,clear <function>清除设置在函数上的断点
#clear <linenum>则清除设置在指定行上的断点
(gdb) clear
Deleted breakpoint 1


#watch命令用于观察变量或表达式的值,watch <expr>为表达式(变量)expr设置一个观察点
#当表达式值有变化时,程序停止执行。注意watchpoint只能在程序启动后设置
#所以先设置一个断点
(gdb) break 6
Breakpoint 1 at 0x4004cc: file sum.c, line 6.
(gdb) run	#启动程序,将在断点处停止
Starting program: /root/sum 

Breakpoint 1, main () at sum.c:6
6		sum = 0;
(gdb) watch sum	#设置观察点
Hardware watchpoint 2: sum
(gdb) c		#使用c命令观察观察点变化
Continuing.
Hardware watct 2: sum

Old value = 0
New value = 1
main () at sum.c:7
7		for(i=0;i<100;i++){ #即将运行的语句
(gdb)

作为入门,此文到此结束。
永久链接:http://blog.ifeeline.com/1081.html

Linux程序设计 – 开发系统导引(C程序编译)

开发系统导引

1 应用程序
2 头文件
用C语言进行程序设计时,需要用头文件来提供对常量的定义和对系统函数及库函数调用的声明。对C语言来说,这些头文件几乎总是位于/usr/include目录及子目录中。

在调用C语言编译器时,可以使用-I标志来包含保存在子目录货非标准位置中的头文件。

用grep命令来搜索包含某些特定定义和函数原型的头文件时很方便的。如想知道用于从程序中放回退出状态的#define定义的名字,只需要切换到/usr/include目录下,然后用grep命令搜索可能的名字:

grep EXIT_ *.h

stdlib.h:#define        EXIT_FAILURE    1       /* Failing exit status.  */
stdlib.h:#define        EXIT_SUCCESS    0       /* Successful exit status.  */

3 库文件
标准系统库文件一般存储在/lib和/usr/lib目录中。C语言编译器(或确切地说是链接程序)需要知道要搜索哪些库文件,因为在默认情况下,它只搜索标准C语言库。

库文件的名字总是以lib开头,随后的部分指明这是什么库(如c代表C语言库,m代表数学库)。文件名的最后部分以.开始,然后给出库文件的类型:

.a	代表传统的静态函数库
.so	代表共享函数库

函数库通常以静态和共享库两种格式存在。

可以通过给出完整的库文件路径或用-l标志告诉编译器要搜索的库文件:

gcc -o fred fred.c /usr/lib/libm.a	#直接给出文件路径

下面的命令也能产生类似结果:

gcc -o fred fred.c -lm			#通过-l指定要使用的库

只要使用ar程序和使用gcc -c命令对函数分别进行编译,就可以创建和维护静态库。例子如下:

vi fred.c
#include <stdio.h>
void fred(int arg)
{
        printf("fred: we passed %d\n",arg);
}

vi bill.c
#include <stdio.h>

void bill(char *arg)
{
        printf("bill: we passed %s\n", arg);
}

##编译成中间文件
gcc -c bill.c fred.c
ls *.o
bill.o  fred.o

##为库文件编写头文件
vi lib.h
void bill(char *);
void fred(int);

##编写一个调用bill函数的程序
vi program.c
#include <stdlib.h>
#include "lib.h"

int main()
{
        bill("Hello World");
        exit(0);
}

##编译program.c
gcc -c program program.c

##链接函数库 生成二进制文件
gcc -o program program.o bill.o  #program只需要用到bill.o

##执行
./program
bill: we passed Hello World

##接下来创建一个库文件
ar crv libfoo.a bill.o free.o

##使用库文件重新链接 生成二进制文件
gcc -o program program.o libfoo.a
./program
bill: we passed Hello World

##也可以使用-l选项来访问函数库,但因其未保存在标准位置,所以必须使用-L选项来告诉编译器在何处找到它
gcc -o program program.o -L. -lfoo

###########
以上-L.选项告诉编译器在当前目录(.)中查找函数库。-lfoo选项告诉编译器使用名为libfoo.a的函数库(或者名为libfoo.so的共享库)。要查看哪些函数被包含在目标文件、函数库或可执行文件里,可以使用nm命令。当程序被创建时,它只包含函数库中它实际需要的函数。虽然程序中的头文件包含函数库中所有函数的声明,但并不会将整个函数库包含在最终的程序中。

5 共享库
共享库的保存位置与静态库是一样的,但共享库有不同的文件名后缀。在一个典型的Linux系统中,标准数学库的共享版本是/usr/lib/libm.so。

当一个程序使用共享库时,它的链接方式是这样的:程序本身不再包含函数代码,而是引用运行时可以访问的共享代码。当编译好的程序被装到内存中执行时,函数引用被解析并产生对共享库的调用,如果有必要,共享库才被加载到内存中。

通过这种方法,系统可以只保留共享库的一份副本供许多应用程序同时使用,并且在磁盘上也仅保存一份。另一个好处是共享库的更新可以独立于依赖它的应用程序。如,文件/lib/bibm.so就是对实际库文件修订版本(/lib/libm/so.N,其中N代表著版本号)的符号链接。

对Linux系统来说,负责装载共享库并解析客户程序函数引用的程序(动态装载器)是ld.so。用于搜索共享库的额外位置可以在文件/etc/ld.so.conf中配置,如果修改了这个文件,需要执行命令ldconfig来处理它。

可以通过运行ldd工具查看一个程序需要的共享库。

永久链接:http://blog.ifeeline.com/1006.html