The book titled: Compiler Design in C, by Allen Holub; page 41 enter image description here has weird syntax, with function definitions, and variable declarations are given inside no opening and closing braces.

第二,无法理解代码行#103的工作原理:

if( (fd =!name? STDIN: (*Openp) (name, O_RDONLY | O_BINARY)) != -1)

即函数调用:

(*Openp) (name, O_RDONLY | O_BINARY)

The function 'Openp' is given on page 40:enter image description herein line #62. Also, the page 39 is attached too, for ease in reference. enter image description here

这本书由作者免费提供.

我试着查看了这本书的序言,以及作者的另一本书,标题是:《C Companion》.

但是,这种语法在任何地方都没有讨论过.

推荐答案

第41页[...]有奇怪的语法,带有函数定义,变量声明没有用左大括号和右大括号.

在该书出版时(1990年),该语法是"traditional"而不是"weird".它是Kernighan&;Richie(K&;R)在The C Programming Language ed.1中定义的语法.在1989年发布用于C的ANSI标准之前,这本书是用于C的de facto标准.毫无疑问,这本书的准备早于C89的出版,对于出版商来说,它在出版时已经过时了,这只是不幸的时机.尽管如此,Prentice Hall也出版了《K&;R;2》.艾德和布莱恩·科尼根编辑了这本书--他们肯定知道吗?此外,前言还声称所有代码都是ANSI C语言,并使用了Microsoft C 5.1.我记得1989年在MS C V6中引入了ANSI C,但我可能错了.5.1于1988年发布--ANSI之前的定稿.他们可能还在委员会里争论这件事;-)版本3.0(1984)是第一个声称与ANSI兼容的版本,但这只是一种猜测,而且只针对当时的早期草案.因此,也许我们可以原谅由于当时语言的变化而造成的混乱.

显然,没有人会废弃庞大的现有代码体,因此实用的编译器会接受任何一种语法--可能是默认情况下.当然,微软更关心的是客户能够构建他们现有的代码,而不是严格执行新标准.

也就是说,本书的主题不是专门的C语言,而是编译实现.也许它仍然有关于编译器实现的相关内容,但您可能需要改编代码示例.

在本例中:

enter image description here

等同于ANSI/ISO C:

void ii_io( int(*open_funct)(), 
            int(*close_funct)(),
            int(*read_funct)() )
{
    ...

在K&;R ed.1 C中,圆括号中的参数列表仅定义参数names,而types定义在该参数和函数的左大括号之间.函数指针语法可能不像更简单的函数接口那样清晰,例如:

int fn( arg1 ) int arg1 { return arg1 ; }

相当于:

int fn( int arg1 ) { return arg1 ; }

如果您try 编译K&;R ed.1代码,您的编译器可能会发出警告,甚至可能会拒绝它,您将不得不设置正在使用的C标准或使用旧的编译器来直接使用代码.

关于:

if( (fd =!name? STDIN: (*Openp) (name, O_RDONLY | O_BINARY)) != -1)

这在ISO C中仍然是有效的代码,所以实际上是另一个问题.Openp是在第76行分配open_funct的某个全局函数指针.如果name是空指针,则布尔表达式!name将是true,在这种情况下,文件描述符fd采用STDIN(宏为stdin流的文件描述符,其为零(在第39页上定义的宏).STDIN没有在标准库中定义,但是POSIX定义了STDIN_FILENO(unistd.h).

如果name不为空,则将所引用的函数Openp(和open_funct)的返回值赋给fd.隐式打开名为name的文件的函数.

关于Openp电话有几件事需要注意:

  1. 首先,显式解引用是可选的--在现代C中肯定是这样,对K&;R C不确定.所以Openp(name, O_RDONLY | O_BINARY)也是有效的.
  2. open_functOpenp的类型-即int(*)()-是一个参数数量未定义的函数,因此可以是指向任何函数的指针,该函数返回具有任何类型的任意数量的参数的int.因此,不可能判断由open_funct提供的函数是否具有正确的signature.额外的参数将被忽略,并且类型可能不匹配.POSIX open()是一个可变函数,允许有和没有mode参数的两个版本(一种"伪"函数重载).没有参数定义允许这样做,但您可以用更严格的:int (*fn)(char*, int, ...)替换这样的定义,以匹配POSIX open()签名,这很可能是本文的目的.

C++相关问答推荐

位屏蔽对于无符号转换是强制的吗?

你能用自己的地址声明一个C指针吗?

C如何显示字符串数组中的第一个字母

来自stdarg.h的c中的va_args无法正常工作<>

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

C中是否有语法可以直接初始化一个常量文本常量数组的 struct 成员?

为什么删除CAP_DAC_OVERRIDE后创建文件失败?

不会停在空格或换行符上的错误

struct 上的OpenMP缩减

在我的代码中,我需要在哪里编写输出函数?

在另一个函数中使用realloc和指针指向指针

Caesar密码调试:输出文本末尾的问号和随机字符

初始成员、公共初始序列、匿名联合和严格别名如何在C中交互?

合并对 struct 数组进行排序

C中的回文数字

如何逐位读取二进制文件?

传递给函数的 struct 中的数组

UpDown控制与预期相反

多行表达式:C 编译器如何处理换行符?

用于内存布局的size命令(文本、数据、bss)