例如:
GetModuleHandleA:
https://docs.microsoft.com/zh-cn/windows/win32/api/libloaderapi/nf- libloaderapi-getmodulehandlea
#1 楼
在C语言和许多其他低级编程语言中,术语NULL
等效于0
。C标准要求将NULL的
#define
d设置为“实现定义值”,但是所有实现都选择了(出于明显的原因)为此使用0
。因此,如果您尝试对NULL
进行“查看定义”,那么许多IDE会将您放置在#define NULL 0
行或类似的行中。 从严格的标准遵循角度来看,正确的方法是使用
NULL
而不是0,这就是大多数开发人员的工作。但是,编译器(或在false
情况下为预处理器)会将其转换为NULL
。一些高级语言(例如javascript和C ++)使用特殊表达式来表示null。一个示例是C ++的
#define NULL 0
,由于C ++ 11是0
的必需定义。 Javascript使用特殊对象nullptr
。评论
评论不作进一步讨论;此对话已移至聊天。
– 0xC0000022L♦
12月7日8:23
#2 楼
在查看Windows API调用或反汇编C / C ++代码时,NULL始终为0,在Visual Studio中,它是在vcruntime.h中定义的。必须为零,例如在.NET C#代码中,例如:#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
将编译为通用中间语言(CIL)。您可以使用ldnull看到null不只是零。
if (args == null)
{
Console.WriteLine("null!");
}
评论
指针上下文中的0在C和C ++中具有特殊含义。此定义不能明确告诉您空指针的对象表示形式为0x00000000。 (在x86的所有主流C ++实现中以及几乎所有主流C和C ++实现中都是这种情况。历史上有一些例外情况:NULL宏何时不为0?在其中提到了一些并引用了C标准re:0源与使用的位模式。)
– Peter Cordes
12月4日16:48
这意味着ISO C ++不保证memset(ptr_array,0,16)会将指针初始化为NULL,或者在OP的情况下,比较将在生成的asm中对照零进行检查。
– Peter Cordes
12月4日16:49
#3 楼
尽管要求将源中的文字0
或(void*)0
(在指针上下文中)评估为空指针,但ISO C和C ++允许实现将非零位模式用作空指针的对象表示。 NULL
。在C或C ++中,基于源定义(例如#define NULL 0
)的推理是不够的。空值。这使像0
这样的不可移植代码按预期工作,等效于将每个元素设置为memset(ptr_array, 0, size)
的循环。在询问源代码级的非零定义,但是我认为这在现代C语言中是不允许的。答案提到了一些具有非零空指针位模式的历史机器。 (即,您会在asm中看到类似NULL
这样的代码)请记住,在asm中,指针只是64位(或32位)整数。
do {...} while(p = p->next);
的整个思想是带内信号传输,不是什么甚至不是指针大小的整数的特殊东西。因此,我们必须选择一个常数。NULL
是一个方便的哨兵值,因为与非检查其他任何值相比,许多ISA在非零值上的分支效率更高。例如ARM有0
可以分支到非零分支,而无需cbnz
。 x86的代码大小优化为cmp
/ test eax, eax
而不是jnz
/ cmp eax, 0
。 (使用CMP reg,0 vs OR reg,reg测试一个寄存器是否为零?)。如果FLAGS已由另一条算术指令设置,则不需要jnz
,但这对于空指针测试是不寻常的:通常,您不先对指针进行数学运算,然后对NULL进行运算。(您没有看到在您的asm中进行了优化,因为您的调试版本会在测试之前存储到内存中。)
另外,
test
很容易生成。在寄存器中创建大量指令可能需要较大的指令或大多数指令。 (例如x86 0
而不是xor eax,eax
)。零初始化静态存储(例如mov eax, imm32
)可以在BSS中而不是static int *table = NULL;
-现代系统对BSS进行零初始化。实际上那里有系统管理的东西,例如中断处理程序表的开始。因此.data
可以是有效地址,也可以等于0
。这有点烂,所以这实际上可能是想要空指针的非零对象表示形式的地方。 @Simon Richter评论了有关如何入侵ARM编译器以将0
用作NULL位模式的问题。确保NULL引用实际上是错误的。 (请记住,C和C ++中的未定义行为不是必需的,但是这样做肯定很方便。)
评论
旁注:我认为最初所有这些方法都记录为在失败时返回零,但现在大多数都切换为“ NULL”,但是您仍然可以找到“零”-docs.microsoft.com/zh-cn/windows/win32/api/ libloaderapi /…(这只是问题中的函数的Ex版本)