Tel*_*hus 5 c macros null struct expression
我对Eric Roberts的C编程抽象中的一些代码有疑问.他使用自己的几个库来简化读者的工作并教授如何编写库.(该书的所有图书馆代码都可以在这个网站上找到.)
一个库genlib提供了一个宏,用于指向struct类型的指针的泛型分配.我不明白宏的一部分.我将复制下面的代码,再加上一个如何使用它的例子,然后我将更详细地解释我的问题.
/*
* Macro: New
* Usage: p = New(pointer-type);
* -----------------------------
* The New pseudofunction allocates enough space to hold an
* object of the type to which pointer-type points and returns
* a pointer to the newly allocated pointer. Note that
* "New" is different from the "new" operator used in C++;
* the former takes a pointer type and the latter takes the
* target type.
*/
#define New(type) ((type) GetBlock(sizeof *((type) NULL)))
/* GetBlock is a wrapper for malloc. It encasulates the
* common sequence of malloc, check for NULL, return or
* error out, depending on the NULL check. I'm not going
* to copy that code since I'm pretty sure it isn't
* relevant to my question. It can be found here though:
* ftp://ftp.awl.com/cseng/authors/roberts/cs1-c/standard/genlib.c
*/
Run Code Online (Sandbox Code Playgroud)
Roberts打算使用如下代码:
typedef struct {
string name;
/* etc. */
} *employeeT;
employeeT emp;
emp = New(employeeT);
Run Code Online (Sandbox Code Playgroud)
他更喜欢使用指向记录的指针作为类型名称,而不是记录本身.因此New提供了分配此类struct记录的通用方法.
在宏观中New,我不明白的是:sizeof *((type)) NULL).如果我正确地阅读它,它会说"将取消引用的强制转换的大小视为给定调用中代表的NULL任何struct类型type".我想我理解解除引用:我们想为结构分配足够的空间; 指针的大小不是我们需要的,所以我们取消引用以获得底层记录类型的大小.但我不明白铸造NULL类型的想法.
我的问题:
NULL?那有什么意思?为什么演员必要?当我尝试删除它时,编译器说error: expected expression.那么,sizeof *(type)不是表达吗?这使我很困惑,因为我可以执行以下操作来获取任意指针到结构的大小:
#define struct_size(s_ptr) do { \
printf("sizeof dereferenced pointer to struct %s: %lu\n", \
#s_ptr, sizeof *(s_ptr)); \
} while(0)
Run Code Online (Sandbox Code Playgroud)编辑:正如下面许多人所指出的,这两个例子不一样:
/* How genlib uses the macro. */
New(struct MyStruct*)
/* How I was using my macro. */
struct MyStruct *ptr; New(ptr)
Run Code Online (Sandbox Code Playgroud)
为了记录,这不是功课.我是一名业余爱好者,试图在C处进行改进.此外,就我所知,代码没有任何问题.也就是说,我不是在问我怎样才能做出与众不同的事情.我只是想更好地理解(1)它是如何工作的,以及(2)为什么它必须以它的方式编写.谢谢.
问题是宏需要获取指针类型指向的类型的大小.
例如,假设您具有指针类型struct MyStruct*.如果不从这个表达式中移除星星,你将如何获得大小struct MyStruct?你不能写
sizeof(*(struct MyStruct*))
Run Code Online (Sandbox Code Playgroud)
因为那不是合法的C代码.
另一方面,如果你有一个类型的变量struct MyStruct*,你可以这样做:
struct MyStruct* uselessPointer;
sizeof(*uselessPointer);
Run Code Online (Sandbox Code Playgroud)
因为sizeof实际上没有评估它的参数(它只是确定表达式类型的静态大小),所以这是安全的.
当然,在宏中,您无法定义新变量.但是,您可以struct MyStruct*通过强制转换现有指针来构成随机指针.在这里,NULL是一个很好的候选人 - 它是一个现有的指针,你可以合法地投射到struct MyStruct*.因此,如果你要写
sizeof(* ((struct MyStruct*)NULL))
Run Code Online (Sandbox Code Playgroud)
代码会
NULL为a struct MyStruct*,产生静态类型的指针struct MyStruct*.struct MyStruct*,它指向一个类型的对象struct MyStruct,因此产生类型struct MyStruct.换句话说,它是一种获取指针类型对象的简单方法,以便您可以取消引用它并获取基础类型的对象.
我曾在其他一些宏上与Eric合作,他是预处理器的真正专业人士.我对此并不感到惊讶,我并不感到惊讶,这很棘手,但它确实很聪明!
作为一个注释 - 在C++中,这种技巧在引入declval实用程序类型之前是常见的,实用程序类型是此操作的一个不太常见的版本.
希望这可以帮助!