📄 protomac.20000601.html
字号:
<html><!-- Mirrored from c-faq.com/style/protomac.20000601.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:02:16 GMT --><head><title></title></head><body><p>[Someone asked me the questionwhich is now 17.4b in the comp.lang.c FAQ list,and this was my reply.]<p>From: scs@eskimo.com (Steve Summit)<br>Subject: Re: A ``C'' Question<br>Date: Thu, 1 Jun 2000 11:43:30 -0700 (PDT)<br>Message-Id: <200006011843.LAA29337@mail.eskimo.com><p>You wrote:<br>> I have a ``C'' programming question. On UNIX system, in /usr/include <br>> directory, there is a ctype.h.<p>As a general rule, you have to be careful when inspectingcompiler-supplied header files, for example the ones in/usr/include. Often these make use of ``magic'' features which arenot standard and sometimes not even intended for users to use.This question, however, has a reasonably straightforward answer,and it's not tied to any particular compiler.<p>> In this file, there is a prototype definition<br>> <TT>extern int isalpha __((int))</TT>.<br>> I can not understand <space><TT>__((int))</TT>. What is meaning of that?<br>> My guess is that it is an argument to the function isalpha but<br>> how come there is a space in between.<p>This is actually a trick.<p>As you may know, there are two kinds of external functionprototype declaration in C. The old-fashioned kind looked like<p><pre> extern int isalpha();</pre>and says that <TT>isalpha</TT> is a function returning <TT>int</TT>. The newer,prototype form (which may be the only kind you're used to) lookslike<p><pre> extern int isalpha(int);</pre>and supplies the additional information that the <TT>isalpha</TT> functionaccepts one argument, of type <TT>int</TT>.<p>Sometimes it's useful if a piece of code (in this case, a headerfile) can be compiled both by ANSI-compatible and pre-ANSIcompilers. Function prototypes, however, were introduced alongwith the ANSI Standard. Pre-ANSI compilers didn't understandfunction prototypes, and in fact a pre-ANSI compiler willgenerally report a ``syntax error'' when it sees a functionprototype.<p>The first half of the trick, therefore, is to make the presenceof the function prototype conditional. Suppose we had the macro<p><pre> #define PROTOTYPE(args) args</pre>This is a fairly useless-looking macro; all it does is accept onemacro argument and spit it back out. But suppose we were towrite the prototype for isalpha as<p><pre> extern int isalpha PROTOTYPE((int));</pre>After the preprocessor expanded the macro, we'd end up with<p><pre> extern int isalpha (int);</pre>which is just like our original prototype (except for theinsertion of an extra space, which doesn't matter).<p>(One additional question here is why we have to invoke themacro as <TT>PROTOTYPE((int))</TT>, with an extra set of parentheses.The reason is so that the preprocessor won't complain when weuse the <TT>PROTOTYPE</TT> macro to help us declare a function that takesmultiple arguments. If we invoked <TT>PROTOTYPE(int, double)</TT>, thepreprocessor would complain that we'd invoked the <TT>PROTOTYPE</TT> macrowith two macro arguments, while it expected only one. But whenwe invoke it as <TT>PROTOTYPE((int, double))</TT>, as far as thepreprocessor is concerned we're invoking it with one argument,which is ``<TT>(int, double)</TT>'', including one pair of parentheses.)<p>Now, however, we have a way to ``turn off'' the prototype. If weredefine the <TT>PROTOTYPE</TT> macro as<pre> #define PROTOTYPE(args) ()</pre>the macro-ized declaration for isalpha would turn into<pre> extern int isalpha ();</pre>and this would be acceptable to a pre-ANSI compiler. So, puttingthis all together, we might say<p><pre> #ifdef __STDC__ #define PROTOTYPE(args) args #else #define PROTOTYPE(args) () #endif extern int isalpha PROTOTYPE((int));</pre><p>Now we have one scrap of code that's ``backwards compatible''to a pre-ANSI compiler. (Obviously we only have to do the<TT>#ifdef</TT>/<TT>#define</TT>/<TT>#else</TT> thing once, then we can use the <TT>PROTOTYPE</TT>macro in lots of external function prototype declarations.)<p>The only problem with this is that<pre> extern int isalpha PROTOTYPE((int));</pre>looks pretty ugly, due to that macro name <TT>PROTOTYPE</TT> sitting inthere. Someone decided that it was worth trying to fix this.<p>The rule for identifiers in C is that they may consist ofletters, digits, and underscore characters, and that the firstcharacter must not be a digit. This means that the firstcharacter <em>can</em> be an underscore. But it also means thatidentifiers consisting of <em>only</em> underscores are legal! Using asingle or a double underscore as an identifier is a pretty sneakytrick, and we obviously can't use it too often, but if we'vedecided that writing backwards-compatible function declarationswithout that ugly <TT>PROTOTYPE</TT> name is so important that we'rewilling to devote this sneaky trick to the task, we can replacethe macro name ``<TT>PROTOTYPE''</TT> with the macro name ``<TT>__</TT>'', leading to:<p><pre> #ifdef __STDC__ #define __(args) args #else #define __(args) () #endif extern int isalpha __((int));</pre><p>So that explains what you saw. (Personally, I don't think thisis all worth it, and I don't use this trick, myself, but I'veseen it in plenty of code written by others.)<p><address><a href="http://www.eskimo.com/~scs/">Steve Summit</a><br><a href="mailto:scs@eskimo.com">scs@eskimo.com</a></address><br>-- <br>Programming Challenge #6: Don't just fix the bug.<br>See <a href="http://www.eskimo.com/~scs/challenge/">http://www.eskimo.com/~scs/challenge/</a>.</body><!-- Mirrored from c-faq.com/style/protomac.20000601.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:02:16 GMT --></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -