<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>五四陈科学院-坚信科学，分享技术 &#187; c</title>
	<atom:link href="http://www.54chen.com/tag/c/feed" rel="self" type="application/rss+xml" />
	<link>http://www.54chen.com</link>
	<description>PHP、JAVA、缓存、架构、经验、分享</description>
	<lastBuildDate>Wed, 08 Feb 2012 08:48:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>普及帖：Linux 下编译C程序</title>
		<link>http://www.54chen.com/_linux_/%e6%99%ae%e5%8f%8a%e5%b8%96%ef%bc%9alinux-%e4%b8%8b%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f.html</link>
		<comments>http://www.54chen.com/_linux_/%e6%99%ae%e5%8f%8a%e5%b8%96%ef%bc%9alinux-%e4%b8%8b%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f.html#comments</comments>
		<pubDate>Fri, 19 Dec 2008 02:28:02 +0000</pubDate>
		<dc:creator>cc0cc</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[c]]></category>

		<guid isPermaLink="false">http://www.54chen.com/_linux_/%e6%99%ae%e5%8f%8a%e5%b8%96%ef%bc%9alinux-%e4%b8%8b%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f.html</guid>
		<description><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br>GNU 编译器集（其前身为GNU C 编译器）诞生于1987年。当时Richard Stallman（GNU 项目的创办人）想要创建一个编译器，它可以满足他定义的“自由软件”概念，并可用来编译 GNU 项目发布的其他软件。GNU C 编译器迅速在自由软件社区中流行开来，而且以其健壮性和可移植性而闻名。它已成为许多集成开发工具的基础，被世界各地的发行商应用在 Linux 和其他操作系统之上。   GCC 已不再是主要针对GNU项目自身的软件的小型 C 语言编译器了。如今，它已支持了许多不同的语言，包括 C、C++、Ada、Fortran、Objective C，甚至还有Java。事实上，现代 Linux 系统除了可以自豪地炫耀那些由 GNU 工具直接支持的语言以外，它还支持大量其他语言。日益流行的脚本语言 Perl、Python 和 Ruby，以及正在不断发展的mono 可移植C#实现的确有助于冲淡人们对 Linux 编程的传统看法，但这完全是另外一个问题了。 Linux 内核和许多其他自由软件以及开放源码应用程序都是用 C 语言编写并使用 GCC 编译的。 1. 编译单个源文件 为了进行测试，你可以创建“Hello World”程序： #include &#8230;<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></description>
			<content:encoded><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br><p>GNU 编译器集（其前身为GNU C 编译器）诞生于1987年。当时Richard Stallman（GNU 项目的创办人）想要创建一个编译器，它可以满足他定义的“自由软件”概念，并可用来编译 GNU 项目发布的其他软件。GNU C 编译器迅速在自由软件社区中流行开来，而且以其健壮性和可移植性而闻名。它已成为许多集成开发工具的基础，被世界各地的发行商应用在 Linux 和其他操作系统之上。</p>
<p> </p>
<p>GCC 已不再是主要针对GNU项目自身的软件的小型 C 语言编译器了。如今，它已支持了许多不同的语言，包括 C、C++、Ada、Fortran、Objective C，甚至还有Java。事实上，现代 Linux 系统除了可以自豪地炫耀那些由 GNU 工具直接支持的语言以外，它还支持大量其他语言。日益流行的脚本语言 Perl、Python 和 Ruby，以及正在不断发展的mono 可移植C#实现的确有助于冲淡人们对 Linux 编程的传统看法，但这完全是另外一个问题了。</p>
<p>Linux 内核和许多其他自由软件以及开放源码应用程序都是用 C 语言编写并使用 GCC 编译的。</p>
<p>1. 编译单个源文件</p>
<p>为了进行测试，你可以创建“Hello World”程序：</p>
<blockquote><p>#include &lt;stdio.h&gt;<br />
#include &lt;stdlib.h&gt;</p>
<p>int main(int argc, char **argv)<br />
{<br />
printf(”Hello world!\n”);<br />
exit(0);<br />
}</p></blockquote>
<p>使用如下命令编译并测试这个代码：<br />
<code># gcc -o hello hello.c<br />
# ./hello<br />
Hello wordl!</code></p>
<p>在默认情况下产生的可执行程序名为a.out，但你通常可以通过 gcc 的“-o”选项来指定自己的可执行程序名称。</p>
<p>2. 编译多个源文件</p>
<p>源文件message.c包含一个简单的消息打印函数：</p>
<blockquote><p>#include &lt;stdio.h&gt;</p>
<p>void goodbye_world(void)<br />
{<br />
printf(”Goodbye, world!\n”);<br />
}</p></blockquote>
<p>使用gcc的“-c”标记来编译支持库代码：<br />
<code># gcc -c message.c</code></p>
<p>这一过程的输出结果是一个名为message.o的文件，它包含适合连接到一个较大程序的已编译目标代码。</p>
<p>创建一个简单的示例程序，它包含一个调用goodbye_world的main函数</p>
<blockquote><p>#include &lt;stdlib.h&gt;</p>
<p>void goodbye_world(void):</p>
<p>int main(int argc, char **argv)<br />
{<br />
goodbye_world();<br />
exit(0);<br />
}</p></blockquote>
<p>使用GCC编译这个程序：<br />
<code># gcc -c main.c</code></p>
<p>现在有了两个目标文件： message.o 和 main.o 。它们包含能够被 Linux 执行的目标代码。要从这个目标代码创建Linux可执行程序，需要再一次调用 GCC 来执行连接阶段的工作：<br />
# gcc -o goodbye message.o main.o</p>
<p>运行编译结果：<br />
<code># ./goodbye<br />
Goodbye, world!</code></p>
<p>前面这些单独的步骤也可以简化为一个命令，这是因为 GCC 对如何将多个源文件编译为一个可执行程序有内置的规则。<br />
<code># gcc -o goodbye message.c main.c<br />
# ./goodbye<br />
Goodbye, world!</code></p>
<p>3. 使用外部函数库</p>
<p>GCC 常常与包含标准例程的外部软件库结合使用，几乎每一个 Linux 应用程序都依赖于由 GNU C 函数库 GLIBC。<br />
应用外部函数库的例子：</p>
<blockquote><p>#include &lt;stdio.h&gt;<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;math.h&gt;</p>
<p>#define MAX_INPUT 25</p>
<p>int main(int agrc, char **argv)<br />
{<br />
char input[MAX_INPUT];<br />
double angle;</p>
<p>printf(”Give me an angle (in radians) ==&gt;”);<br />
if(!fgets(input, MAX_INPUT, stdin)){<br />
perror(”an error occurred.\n”);<br />
}<br />
angle = strtod(input, NULL);</p>
<p>printf(”sin(%e) = %e\n”, angle, sin(angle));</p>
<p>return 0;<br />
}</p></blockquote>
<p>编译命令：<br />
<code># gcc -o trig -lm trig.c</code></p>
<p>GCC 的”-lm”选项，它告诉 GCC 查看系统提供的数学库（libm）。因为Linux和UNIX的系统函数库通常以”lib”为前缀，所以我们假设它存在。真正的函数库位置随系统的不同而不同，但它一般会位于目录/lib或/usr/lib中，在这些目录中还有数以百计的其他必需的系统函数库。</p>
<p>4. 共享函数库与静态函数库</p>
<p>Linux系统上的函数库分为两种不同的类型：共享的和静态的</p>
<p>静态函数库：每次当应用程序和静态连接的函数库一起编译时，任何引用的库函数中的代码都会被直接包含进最终的二进制程序。</p>
<p>共享函数库：包含每个库函数的单一全局版本，它在所有应用程序之间共享。这一过程背后所涉及的机制相当复杂，但主要依靠的是现代计算机的虚拟内存能力，它允许包含库函数的物理内存安全地在多个独立用户程序之间共享。</p>
<p>使用共享函数库不仅减少了文件的容量和 Linux 应用程序在内存中覆盖的区域，而且它还提高了系统的安全性。一个被许多不同程序同时调用的共享函数库很可能会驻留在内存中，以在需要使用它时被立即使用，而不是位于磁盘的交换分区中。这有助于进一步减少一些大型 Linux 应用程序的装载时间。</p>
<p>将上面的 message.c 作为共享库函数使用的例子：</p>
<p><code># gcc -fPIC -c message.c</code><br />
“PIC”命令行标记告诉 GCC 产生的代码不要包含对函数和变量具体内存位置的引用，这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译输出的文件 message.o 可以被用于建立共享函数库，我们只需使用gcc的“-shared”标记即可：<br />
<code># gcc -shared -o libmessage.so message.o</code></p>
<p>将上面的mian.c使用共享库函数ligmessage.so编译：<br />
<code># gcc -o goodbye -lmessage -L. message.o</code><br />
“-lmessage”标记来告诉 GCC 在连接阶段引用共享函数库 libmessage.so 。“-L.”标记告诉 GCC 函数库可能位于当前目录中，否则 GNU 的连接器会查找标准系统函数库目录，在本例的情况下，就找不到可用的函数库了。</p>
<p>此时运行编译好的goodbye会提示找不到共享函数库：<br />
<code>#./goodbye<br />
./goodbye: error while loading shared libraries: libmessage.so: cannot open shared object file: No such file or directory</code></p>
<p>可以使用命令 ldd 来发现一个特定应用程序需要使用的函数库。ldd搜索标准系统函数库路径并显示一个特定程序使用的函数库版本。</p>
<blockquote><p>#ldd goodbye<br />
linux-gate.so.1 =&gt;  (0×00493000)<br />
libmessage.so =&gt; not found<br />
libc.so.6 =&gt; /lib/libc.so.6 (0×0097c000)<br />
/lib/ld-linux.so.2 (0×0095a000)</p></blockquote>
<p>库文件 libmessage.so 不能在任何一个标准搜索路径中找到，而且系统提供的配置文件 /etc/ld.so.conf 也没有包含一个额外的条目来指定包含该库文件的目录。</p>
<p>需要设置一个环境变量LD_LIBRARY_PATH来制定额外的共享函数库搜索路径，<br />
<code># export LD_LIBRARY_PATH=`pwd`<br />
# ldd goodbye<br />
linux-gate.so.1 =&gt;  (0x002ce000)<br />
libmessage.so =&gt; /tmp/cpro/libmessage.so (0x00b0f000)<br />
libc.so.6 =&gt; /lib/libc.so.6 (0x0097c000)<br />
/lib/ld-linux.so.2 (0x0095a000)</code><br />
运行程序<br />
<code># ./goodbye<br />
Goodbye, world!</code></p>
<p>gcc在命令行上经常使用的几个选项是：<br />
-c   只预处理、编译和汇编源程序，不进行连接。编译器对每一个源程序产生一个目标文件。<br />
-o file  确定输出文件为file。如果没有用-o选项，缺省的可执行文件的输出是 a.out，目标文件和汇编文件的输出对source.suffix分别是source.o和source.s，预处理的C源程序的输出是标准输出stdout。<br />
-Dmacro或-Dmacro=defn   其作用类似于源程序里的#define。例如：% gcc -c -DHAVE_GDBM -DHELP_FILE=\”help\” cdict.c其中第一个- D选项定义宏HAVE_GDBM，在程序里可以用#ifdef去检查它是否被设置。第二个-D选项将宏HELP_FILE定义为字符串“help”（由于反斜线的作用，引号实际上已成为该宏定义的一部分），这对于控制程序打开哪个文件是很有用的。<br />
-Umacro   某些宏是被编译程序自动定义的。这些宏通常可以指定在其中进行编译的计算机系统类型的符号，用户可以在编译某程序时加上 -v选项以查看gcc缺省定义了哪些宏。如果用户想取消其中某个宏定义，用-Umacro选项，这相当于把#undef macro放在要编译的源文件的开头。<br />
-Idir   将dir目录加到搜寻头文件的目录列表中去，并优先于在gcc缺省的搜索目录。在有多个-I选项的情况下，按命令行上-I选项的前后顺序搜索。dir可使用相对路径，如-I../inc等。<br />
-O   对程序编译进行优化，编译程序试图减少被编译程序的长度和执行时间，但其编译速度比不做优化慢，而且要求较多的内存。<br />
-O2   允许比-O更好的优化，编译速度较慢，但结果程序的执行速度较快。<br />
-g   产生一张用于调试和排错的扩展符号表。-g选项使程序可以用GNU的调试程序GDB进行调试。优化和调试通常不兼容，同时使用-g和-O（-O2）选项经常会使程序产生奇怪的运行结果。所以不要同时使用-g和-O（-O2）选项。<br />
-fpic或-fPIC   产生位置无关的目标代码，可用于构造共享函数库。<br />
以上是gcc的编译选项。gcc的命令行上还可以使用连接选项。事实上，gcc将所有不能识别的选项传递给连接程序ld。连接程序ld将几个目标文件和库程序组合成一个可执行文件，它要解决对外部变量、外部过程、库程序等的引用。但我们永远不必要显式地调用ld。利用gcc命令去连接各个文件是很简单的，即使在命令行里没有列出库程序，gcc也能保证某些库程序以正确的次序出现。<br />
gcc的常用连接选项有下列几个：<br />
-Ldir   将dir目录加到搜寻-l选项指定的函数库文件的目录列表中去，并优先于gcc缺省的搜索目录。在有多个-L选项的情况下，按命令行上-L选项的前后顺序搜索。dir可使用相对路径。如-L../lib等。<br />
-lname   在连接时使用函数库libname.a，连接程序在-Ldir选项指定的目录下和/lib，/usr/lib目录下寻找该库文件。在没有使用-static选项时，如果发现共享函数库libname.so，则使用libname.so进行动态连接。<br />
-static   禁止与共享函数库连接。<br />
-shared   尽量与共享函数库连接。<br />
这是Linux上连接程序的缺省选项。下面是一个使用gcc进行连接的例子：<br />
<code>% gcc -o prog main.o subr.o -L../lib -lany -lm</code></p>
<p>From:<a href="http://www.ownlinux.cn/2008/11/14/linux-gcc-c/">http://www.ownlinux.cn/2008/11/14/linux-gcc-c/</a></p>
<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></content:encoded>
			<wfw:commentRss>http://www.54chen.com/_linux_/%e6%99%ae%e5%8f%8a%e5%b8%96%ef%bc%9alinux-%e4%b8%8b%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>坐阵杭州淘宝</title>
		<link>http://www.54chen.com/life/%e5%9d%90%e9%98%b5%e6%9d%ad%e5%b7%9e%e6%b7%98%e5%ae%9d.html</link>
		<comments>http://www.54chen.com/life/%e5%9d%90%e9%98%b5%e6%9d%ad%e5%b7%9e%e6%b7%98%e5%ae%9d.html#comments</comments>
		<pubDate>Wed, 17 Dec 2008 07:05:22 +0000</pubDate>
		<dc:creator>cc0cc</dc:creator>
				<category><![CDATA[生活备份]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[备忘]]></category>

		<guid isPermaLink="false">http://www.54chen.com/life/%e5%9d%90%e9%98%b5%e6%9d%ad%e5%b7%9e%e6%b7%98%e5%ae%9d.html</guid>
		<description><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br>照片欠奉。 涉及到技术转型，看到一句话，共勉。 如果程序语言是宗教，那么： C语言是犹太教，Java是基督教，c++是回教. C#是摩門教，LISP是禪宗佛教，PHP是Cafeteria基督教，Haskell是道教，Erlang是印度教，Perl是伏都教，Lua是巫术，Ruby是新异教主义，Python是世俗人文主义，COBOL是古异教主义，APL是山达基教，Visual Basic是撒旦教。<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></description>
			<content:encoded><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br><p>照片欠奉。</p>
<p>涉及到技术转型，看到一句话，共勉。</p>
<p>如果程序语言是宗教，那么： C语言是犹太教，Java是基督教，c++是回教. C#是摩門教，LISP是禪宗佛教，PHP是Cafeteria基督教，Haskell是道教，Erlang是印度教，Perl是伏都教，Lua是巫术，Ruby是新异教主义，Python是世俗人文主义，COBOL是古异教主义，APL是山达基教，Visual Basic是撒旦教。</p>
<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></content:encoded>
			<wfw:commentRss>http://www.54chen.com/life/%e5%9d%90%e9%98%b5%e6%9d%ad%e5%b7%9e%e6%b7%98%e5%ae%9d.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>究竟什么是TSRMLS_CC？</title>
		<link>http://www.54chen.com/php-tech/what-is-tsrmls_cc.html</link>
		<comments>http://www.54chen.com/php-tech/what-is-tsrmls_cc.html#comments</comments>
		<pubDate>Wed, 03 Dec 2008 11:21:30 +0000</pubDate>
		<dc:creator>cc0cc</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[资料文档]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[php扩展]]></category>

		<guid isPermaLink="false">http://www.54chen.com/php-tech/what-is-tsrmls_cc.html</guid>
		<description><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br>翻译：54chen.com 原文地址：http://blog.libssh2.org/index.php?/archives/22-What-the-heck-is-TSRMLS_CC-anyway.html 如果你曾经做过php内核或者是php扩展方面的工作，你一定见到过这个到处都是的结构，但是却从来没有人提起过它。知道这是什么的人典型回答不知道的人都会这样说：“不用管它是什么，只需要在这里、这里还有这里用，如果编译器说少一个tsrm_ls，就加一个...”。这样回答并非都是因为这个人懒惰（的确是有一点点懒），其实那只是在说引擎甚至可以不管这个神奇的值在简化什么，这是因为一个新入门的扩展开发者知道它的结构没有什么益处。这信息就像奶牛的意见一样，没关系，就是牛叫而已。 既然我喜欢听自己喋喋不休的无意义主题（这个月我已经少写很多博客了），我想我得弥补这一主题，看看会不会有人通过他能领会什么。你可以责怪Lukas(Lukas Smith 是 PEAR DB 的主要作者应该是这个Lukas，译者注)，他让我一直在planet-php.net上。 术语 TSRM Thread Safe Resource Manager - 这是一个经常被忽视的层面，就会有也是很少被讨论到，在你的PHP源代码包中，它被隐藏在/TSRM目录中。默认情况下，TSRM 层只在编译需要它的SAPI的时候才会打开（例如apache2-worker）。所有的在win32下编译的SAPI都会有TSRM层而不会管它们是否需要。 ZTS Zend Thread Ssafety -通常情况下，与TSRM有相同的用处。具体来说不同在于，ZTS的使用需要在编译的时候加上参数如./configure ( --enable-experimental-zts for PHP4, --enable-maintainer-zts for PHP5），而TSRM是否被使用是由#define的预处理机制来确定的。 tsrm_ls TSRM local storage - 当ZTS可用时，这是它在TSRMLS_*宏里传来传去的实际的变量名。它作为一个指向那个线程的独立数据存储块开始位置的指针，我会在一会儿后将它覆盖掉。 TSRMLS_?? 有四个宏设计来为了使ZTS模式和非ZTS模式之间的差异变得平滑，当ZTS不能用时，这四个宏同时都没有任何用处。而在ZTS启用的时候，它们扩大了以下的定义： TSRMLS_C   tsrm_ls TSRMLS_D   void &#8230;<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></description>
			<content:encoded><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br><blockquote><p>翻译：<a href="http://www.54chen.com">54chen.com</a></p></blockquote>
<p>原文地址：<a href="http://blog.libssh2.org/index.php?/archives/22-What-the-heck-is-TSRMLS_CC-anyway.html">http://blog.libssh2.org/index.php?/archives/22-What-the-heck-is-TSRMLS_CC-anyway.html</a></p>
<p>如果你曾经做过php内核或者是<a href="http://www.54chen.com/c/91">php扩展</a>方面的工作，你一定见到过这个到处都是的结构，但是却从来没有人提起过它。知道这是什么的人典型回答不知道的人都会这样说：“不用管它是什么，只需要在这里、这里还有这里用，如果编译器说少一个tsrm_ls，就加一个...”。这样回答并非都是因为这个人懒惰（的确是有一点点懒），其实那只是在说引擎甚至可以不管这个神奇的值在简化什么，这是因为一个新入门的扩展开发者知道它的结构没有什么益处。这信息就像奶牛的意见一样，没关系，就是牛叫而已。</p>
<p>既然我喜欢听自己喋喋不休的无意义主题（这个月我已经少写很多博客了），我想我得弥补这一主题，看看会不会有人通过他能领会什么。你可以责怪Lukas(Lukas Smith 是 PEAR DB 的主要作者应该是这个Lukas，译者注)，他让我一直在<a href="http://www.planet-php.net/">planet-php.net</a>上。</p>
<p><strong>术语</strong></p>
<p>TSRM</p>
<p><strong>T</strong>hread <strong>S</strong>afe <strong>R</strong>esource <strong>M</strong>anager - 这是一个经常被忽视的层面，就会有也是很少被讨论到，在你的<a href="http://www.54chen.com/c/61">PHP源代码</a>包中，它被隐藏在/TSRM目录中。默认情况下，TSRM 层只在编译需要它的SAPI的时候才会打开（例如apache2-worker）。所有的在win32下编译的SAPI都会有TSRM层而不会管它们是否需要。</p>
<p>ZTS</p>
<p><strong>Z</strong>end <strong>T</strong>hread <strong>S</strong>safety -通常情况下，与TSRM有相同的用处。具体来说不同在于，ZTS的使用需要在编译的时候加上参数如<span style="font-family: courier;">./configure</span> ( <span style="font-family: courier;">--enable-experimental-zts</span> for PHP4, <span style="font-family: courier;">--enable-maintainer-zts</span> for PHP5），而TSRM是否被使用是由#define的预处理机制来确定的。</p>
<p>tsrm_ls</p>
<p>TSRM <strong>l</strong>ocal <strong>s</strong>torage - 当ZTS可用时，这是它在TSRMLS_*宏里传来传去的实际的变量名。它作为一个指向那个线程的独立数据存储块开始位置的指针，我会在一会儿后将它覆盖掉。</p>
<p>TSRMLS_??</p>
<p>有四个宏设计来为了使ZTS模式和非ZTS模式之间的差异变得平滑，当ZTS不能用时，这四个宏同时都没有任何用处。而在ZTS启用的时候，它们扩大了以下的定义：</p>
<li><span style="font-family: courier;">TSRMLS_C   tsrm_ls</span></li>
<li><span style="font-family: courier;">TSRMLS_D   void ***tsrm_ls</span></li>
<li><span style="font-family: courier;">TSRMLS_CC  , tsrm_ls</span></li>
<li><span style="font-family: courier;">TSRMLS_DC  , void ***tsrm_ls</span></li>
<p><span style="font-family: Courier;"><strong>综述</strong></span></p>
<p><span style="font-family: Courier;">在任何普通的C程序（PHP也一样）中，要在两个不同的函数间传递相同的数据块，你两种办法。</span></p>
<p><span style="font-family: Courier;">第一种方法是通过函数的参数传递值：</span></p>
<blockquote>
<pre>#include &lt;stdio.h&gt;

void output_func(char *message)
{
    printf("%s\n", message);
}

int main(int argc, char *argv[])
{
    output_func(argv[0]);

    return 0;
}</pre>
</blockquote>
<pre>另一种方法，你可以把这个值保存在一个上层的全局变量中，让函数通过它来取得：</pre>
<blockquote>
<pre>#include &lt;stdio.h&gt;

char *message;

void output_func(void)
{
    printf("%s\n", message);
}

int main(int argv, char *argv[])
{
    message = argv[0];
    output_func();

    return 0;
}</pre>
</blockquote>
<p>这两种方法各有优点和缺点，而且在在实际应用中你常常会看到两者结合使用。事实上，PHP里到处都是全局变量，从类型标识符，到函数回调指针，再到请求特殊的信息例如用于存储用户空间变量的符号表。试图通过函数参数的方法来传递那些变量是不方便的，例如PHP这样的应用常常会需要去注册回调方法来给不支持上下文数据的外部的库使用，此时使用参数传递是不可能的。</p>
<p>因此，共同的信息，像执行栈、函数表、类表以及扩展登记表都是在全局范围里进行声明的，以便它们能在整个应用的任何一个位置都能使用。对于单线程的SAPIs，例如CLI、APACHE1，或者甚至Apache2-prefork，这样做都是完美的。在RINIT/Activation 阶段，请求具体结构被初始化，并在RSHUTDOWN/Deactivation 阶段重新设置回初始的值等待下一次的请求。一个像APACHE1这样特定的WEB服务器，可以一次处理多个页面，是因为它会产生多个进程，每个进程会在自己的进程空间内使用自己的全局变量副本。</p>
<p>现在，让我们来介绍像Apache2-worker或者IIS这样的线程服务器。在这种情况下，在指定时间里只有一个进程空间是可用的，由它抛出多线程处理。每一个线程都会类似一个单独的进程的方式工作。在处理请求的时候服务会一次一个地来。当两个或者多个<a href="http://www.54chen.com/c/71">线程</a>去处理同一时间的一个请求的时候，麻烦就出现了。每个<a href="http://www.54chen.com/c/73">线程</a>都试图去使用全局变量来保存它的特定请求信息，并尝试写向同样的存储空间。这样子最少会导致一个脚本里声明的用户空间变量在另一个脚本中出现。而在实践中，这样会导致快速灾难性的错误和不可预测的情况，因为内存可以释放两次或者独立的线程写了相互矛盾的信息。</p>
<p><strong>不全的全局</strong></p>
<p>解决方案需要一个引擎、一个核心，还有任何一个使用全局存储的<a href="http://www.54chen.com/c/91">扩展</a>都要决定会使用多少内存给具体的请求数据。然后，在运行的每一个新的线程中，给它们每个分配一块内存，用来存储它们的数据，从而使每个线程都有自己的本地存储。为了把所有的被指定线程用到的内存块聚成一组，最后一个指针向量被开辟来保存子结构的指针。这个指针指向tsrm_ls变量，被TSRMLS_*家族的宏所使用。为了看清它是怎么工作的，我们先来看一个扩展的例子：</p>
<blockquote>
<pre>typedef struct _zend_myextension_globals {
    int foo;
    char *bar;
} zend_myextension_globals;

#ifdef ZTS
int myextension_globals_id;
#else
zend_myextension_globals myextension_globals;
#endif

/* Triggered at the beginning of a thread */
static void php_myextension_globals_ctor(zend_myextension_globals *myext_globals TSRMLS_DC)
{
    myext_globals-&gt;foo = 0;
    myext_globals-&gt;bar = NULL;
}

/* Triggered at the end of a thread */
static void php_myextension_globals_dtor(zend_myextension_globals *myext_globals TSRMLS_DC)
{
    if (myext_globals-&gt;bar) {
        efree(myext_globals-&gt;bar);
    }
}

PHP_MINIT_FUNCTION(myextension)
{
#ifdef ZTS
    ts_allocate_id(&amp;myextension_globals_id, sizeof(zend_myextension_globals),
                   php_myextension_globals_ctor, php_myextension_globals_dtor);
#else
    php_myextension_globals_ctor(&amp;myextension_globals TSRMLS_CC);
#endif

    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(myextension)
{
#ifndef ZTS
    php_myextension_globals_dtor(&amp;myextension_globals TSRMLS_CC);
#endif

    return SUCCESS;
}</pre>
</blockquote>
<p>这里可以看到，扩展在启动的时候声明了它全局需求的变量给TSRM层，它需要sizeof(zend_myextension_globals)字节的存储，并且在初始化或者销毁指定的线程的本地存储的时候提供了回调函数。myextension_globals_id里的值可得出偏移量（对所有线程是公共的），存储于tsrm_ls向量，指向那个线程本地存储的指针中也是这个向量。如果ZTS不能用，数据存储只不过是放在真实的全局环境中，并且在线程初始和销毁的过程中需要手动执行初始化和销毁的程序。如果你现在想知道为什么<span style="font-family: courier;">TSRMLS_CC</span> 被包含在非ZTS块中，那我可以很确定我没有使你看睡着了。这些都是不是必须的，因为我们知道非ZTS里他们有和没有一个样，但这有助于鼓励函数原型调用时引用它们的好习惯。</p>
<p><strong>把它们聚在一起</strong></p>
<p>最后一块线程安全的疑惑来自于一个问题：“我如何获得这些数据结构？”这个问题的答案来自于另一个有着相似样子的宏。在每个扩展或者是核心组件定义的头文件中，有一个宏的定义如下所示：</p>
<blockquote>
<pre>#ifdef ZTS
# define   MYEXTENSION_G(v)     \
             (((zend_myextension_globals*)(*((void ***)tsrm_ls))[(myextension_globals_id)-1])-&gt;v)
#else
# define   MYEXTENSION_G(v)     (myextension_globals.v)
#endif</pre>
</blockquote>
<p>因此，当ZTS不可用时，这个宏简单地收集来自全局环境中的即时值作用正确的值，否则，它将根据ID将结构开辟在本线程的本地存储拷贝中，并且从那里引用到值。</p>
<p>【结束：54chen.com】</p>
<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></content:encoded>
			<wfw:commentRss>http://www.54chen.com/php-tech/what-is-tsrmls_cc.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>sscanf函数的各种用法</title>
		<link>http://www.54chen.com/php-tech/sscanf%e5%87%bd%e6%95%b0%e7%9a%84%e5%90%84%e7%a7%8d%e7%94%a8%e6%b3%95.html</link>
		<comments>http://www.54chen.com/php-tech/sscanf%e5%87%bd%e6%95%b0%e7%9a%84%e5%90%84%e7%a7%8d%e7%94%a8%e6%b3%95.html#comments</comments>
		<pubDate>Tue, 02 Dec 2008 08:05:10 +0000</pubDate>
		<dc:creator>cc0cc</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[php扩展]]></category>
		<category><![CDATA[sscanf]]></category>

		<guid isPermaLink="false">http://www.54chen.com/php-tech/sscanf%e5%87%bd%e6%95%b0%e7%9a%84%e5%90%84%e7%a7%8d%e7%94%a8%e6%b3%95.html</guid>
		<description><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br>sscanf是一个运行时函数，原形很简单：  int sscanf(  const char *buffer,  const char *format [,  argument ] ...  );  它强大的功能体现在对format的支持上。  sscanf与scanf类似，都是用于输入的，只是后者以屏幕(stdin)为输入源，前者以固定字符串为输入源。  　   char str[512] = ;  　　sscanf("123456 ", "%s", str);  　　printf("str=%s", str); 输出 str=123456 　   sscanf("123456 ", "%4s", str);  　　printf("str=%s", str); 输出 str = 1234 　　sscanf("123456 abcdedf", "%[^ ]", str);  　　printf("str=%s", str); 输出 str=123456 (遇到空格为止) 　　sscanf("123456abcdedfBCDEF", "%[^A-Z]", str);  　　printf("str=%s", str); 输出 str=123456abcdef (遇到指定字符为止) &#8230;<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></description>
			<content:encoded><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br><div>
<p>sscanf是一个运行时函数，原形很简单： <br />
int sscanf( <br />
const char *buffer, <br />
const char *format [, <br />
argument ] ... <br />
); <br />
它强大的功能体现在对format的<a href="http://www.54chen.com/c/132">支持</a>上。 </p>
<p>sscanf与scanf类似，都是用于<a href="http://www.54chen.com/c/75">输入</a>的，只是后者以屏幕(stdin)为输入源，前者以固定字符串为输入源。 </p>
<blockquote><p>　   char str[512] = ; <br />
　　sscanf("123456 ", "%s", str); <br />
　　printf("str=%s", str);</p></blockquote>
<p><a href="http://www.54chen.com/c/61">输出</a> str=123456</p>
<blockquote><p>　   sscanf("123456 ", "%4s", str); <br />
　　printf("str=%s", str);</p></blockquote>
<p>输出 str = 1234</p>
<blockquote><p>　　sscanf("123456 abcdedf", "%[^ ]", str); <br />
　　printf("str=%s", str);</p></blockquote>
<p>输出 str=123456 (遇到<a href="http://www.54chen.com/c/22">空格</a>为止)</p>
<blockquote><p>　　sscanf("123456abcdedfBCDEF", "%[^A-Z]", str); <br />
　　printf("str=%s", str);</p></blockquote>
<p>输出 str=123456abcdef (遇到指定<a href="http://www.54chen.com/c/22">字符</a>为止)</p>
<blockquote><p>sscanf(mod, "%s", mod);//去除空格</p></blockquote>
</div>
<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></content:encoded>
			<wfw:commentRss>http://www.54chen.com/php-tech/sscanf%e5%87%bd%e6%95%b0%e7%9a%84%e5%90%84%e7%a7%8d%e7%94%a8%e6%b3%95.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>linux下系统托盘的实现</title>
		<link>http://www.54chen.com/web-ral/linux-system-tray-under-the-realization-of.html</link>
		<comments>http://www.54chen.com/web-ral/linux-system-tray-under-the-realization-of.html#comments</comments>
		<pubDate>Fri, 13 Oct 2006 14:47:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[WEB相关]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[系统托盘实现]]></category>

		<guid isPermaLink="false">http://www.54chen.com/web-ral/linux-system-tray-under-the-realization-of.html</guid>
		<description><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br>[文章作者：陈臻 本文版本：v1.0 最后修改：2006.10.13 转载请注明原文链接：http://www.54chen.com/c/24] 在gnome中国的网页上找到这个内容，他们把它叫做“通知功能图标”。它是一个在未来版本中决定发布的已实现包。 http://www.gnome-cn.org/documents/tutorial/system-tray-icon-application/implement-your-tray 具体实现前需要在下载两个开发补丁源文件，然后包含头文件到你的文件中。 具体代码： void create_tray (tray_demo * tray) { GtkWidget *image; GtkWidget *event_box; GtkTooltips *tooltips; EggTrayIcon *tray_icon; tooltips = gtk_tooltips_new (); tray_icon = egg_tray_icon_new ("Tray icon demo"); event_box = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (tray_icon), event_box); &#8230;<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></description>
			<content:encoded><![CDATA[<a href="http://www.54chen.com"><img border="0" src="http://www.54chen.com/wp-content/themes/54chen2011/images/54chen-logo.gif"></a><br>以下内容由<a href="http://www.54chen.com">[五四陈科学院]</a>提供<br><p>[文章作者：陈臻 本文版本：v1.0 最后修改：2006.10.13 转载请注明原文链接：<a href="http://www.54chen.com/c/24">http://www.54chen.com/c/24</a>]<br />
在gnome中国的网页上找到这个内容，他们把它叫做“通知功能图标”。它是一个在未来版本中决定发布的已实现包。</p>
<p>http://www.gnome-cn.org/documents/tutorial/system-tray-icon-application/implement-your-tray</p>
<p>具体实现前需要在下载两个开发补丁源文件，然后包含头文件到你的文件中。<br />
具体代码：<br />
void<br />
create_tray (tray_demo * tray)<br />
{<br />
GtkWidget *image;<br />
GtkWidget *event_box;<br />
GtkTooltips *tooltips;<br />
EggTrayIcon *tray_icon;<br />
tooltips = gtk_tooltips_new ();<br />
tray_icon = egg_tray_icon_new ("Tray icon demo");<br />
event_box = gtk_event_box_new ();<br />
gtk_container_add (GTK_CONTAINER (tray_icon), event_box);<br />
g_signal_connect (G_OBJECT (event_box), "button-press-event",<br />
G_CALLBACK (tray_button_press_event_cb), tray);<br />
gtk_tooltips_set_tip (GTK_TOOLTIPS(tooltips), event_box, _("Try a left/right click"), NULL);<br />
image = load_image (GCN_ICON);<br />
gtk_container_add (GTK_CONTAINER (event_box), image);<br />
gtk_widget_show_all (GTK_WIDGET (tray_icon));<br />
return;<br />
}</p>
<br><br>想快点找到作者也可以到Twitter上留言: <a href="https://www.twitter.com/54chen" target="_blank">@54chen</a><br>或者你懒得带梯子上墙，请到新浪微博：<a href="http://t.sina.com.cn/54chen" target="_blank">@54chen</a>]]></content:encoded>
			<wfw:commentRss>http://www.54chen.com/web-ral/linux-system-tray-under-the-realization-of.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

