简体   繁体   English

在C中使用(char *)0有什么特殊的方法吗?

[英]is there any special approach to using (char *) 0 in C?

I understand that (char *) 0 is a char pointer which points an address at 0. So there is no memory address, out of bound. 我知道(char *) 0是将地址指向(char *) 0的char指针。因此,没有超出范围的内存地址。 Often, I hav seen people using it instead of NULL , so why don't they just simply use NULL ? 我经常看到人们使用它而不是NULL ,那么为什么他们不只是使用NULL Or, I would like to know, whether there is any special approach to it. 或者,我想知道是否有任何特殊方法。

A null pointer is strictly speaking no valid address encoding: 空指针严格来说是无效的地址编码:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. 一个值为0的整数常量表达式,或将这种类型强制转换为void *类型的表达式称为空指针常量。66)如果将空指针常量转换为指针类型,则生成的指针称为空指针。保证比较不等于指向任何对象或函数的指针。

Thus I try to avoid the phrase "address 0" when it comes to null pointers , because this is the encoding and a null pointer need not have all bits zero. 因此,在涉及空指针时 ,我尝试避免使用短语“地址0”,因为这是编码方式,并且空指针不必将所有位都设置为零。 An architecture could - for instance - use an unused bit in the pointer variables to tag it as invalid. 例如,架构可以使用指针变量中未使用的位将其标记为无效。 For comparision eg bitops would be used instead of compare. 为了进行比较,例如将使用位运算代替比较。

The most common encoding is "all bits zero", though so I will mostly concentrate on this. 尽管最常见的编码是“所有位均为零”,所以我将主要集中在此方面。 This encoding is used because most CPUs have special (and shorter/faster) instructions to store a bit value of 0x0 into a memory cell and compare with/test for 0x0 . 之所以使用这种编码,是因为大多数CPU都有特殊(且更短/更快)的指令将0x0的位值存储到存储单元中并与0x0进行比较/测试。 Using a special bitpattern also makes comparing two pointers straight forward, using a single compare. 使用特殊的位模式还可以使用单个比较直接比较两个指针。 The version with setting a dedicated bit would require additional instructions. 设置了专用位的版本将需要其他说明。

Also a value which is at the edge of the address range avoids gaps. 此外,位于地址范围边缘的值可避免出现间隙。 This is true for "all bits 1", too, but with less CPU support and address-width dependency. “所有位1”也是如此,但CPU支持和地址宽度依赖性较小。


Note that most architectures very well do have a valid physical address 0 , so there is in fact a problem with this encoding for a null pointer without address translation. 请注意,大多数架构的确有一个有效的物理地址0 ,因此对于没有地址转换的空指针 ,这种编码实际上存在问题。 Luckily this is typically a special address and not used by normal application code. 幸运的是,这通常是一个特殊的地址,普通的应用程序代码不使用。 With virtual memory addressing, it is quite easy just to make address 0x0 invalid, so this is out of discussion. 使用虚拟内存寻址时,仅使地址0x0无效是非常容易的,因此不再讨论。

On some systems, address 0x0 is used for code (PC-boot code/BIOS, embedded systems) or data-accesses (RAM/peripheral hardware registers). 在某些系统上,地址0x0用于代码(PC引导代码/ BIOS,嵌入式系统)或数据访问(RAM /外围硬件寄存器)。 Strictly speaking you cannot convert the integer-constant 0 to a pointer without invoking the implicit conversion to a null pointer. 严格来说,如果不将隐式转换调用为空指针,就无法将整数常数 0转换为指针。 So, if your system does not use the 0x0 encoding, there is a problem accessing address 0x0 with standard C syntax only. 因此,如果您的系统不使用0x0编码,则仅使用标准C语法访问地址0x0会出现问题。 (FYI: this is one reason other languages use a special keyword for a null pointer constant , eg pascal NIL , Python None , C++ nullptr .) (仅供参考:这是其他语言为空指针常量使用特殊关键字的原因之一,例如pascal NIL ,Python None ,C ++ nullptr 。)

The conversion of an integer to a pointer is implementation defined anyway, as is the null pointer encoding. 无论如何,将整数转换为指针都是由实现定义的, 空指针编码也是如此。 Thus the conversion of a 0 to a pointer is well in-line with the common copy-only integer->pointer encoding without modification of the representation. 因此,从0到指针的转换与常见的仅复制整数->指针编码完全一致,而无需修改表示形式。

A problem arises when dereferencing such a pointer. 取消引用此类指针时会出现问题。 Dereferencing a null pointer is undefined behaviour (UB). 取消引用空指针是未定义的行为(UB)。 As both encodings are identical, there is no way for the CPU to detect if this is a valid access or a null pointer dereferencing. 由于两种编码相同,因此CPU无法检测到这是有效访问还是空指针取消引用。 Even worse: the compiler is free to exploit this UB and generate arbitrary code (or none at all) if it detects something like char c = *((char *)0); 更糟糕的是:如果编译器检测到类似char c = *((char *)0);东西,则可以自由利用此UB并生成任意代码(或根本不生成任何代码char c = *((char *)0); .

For a true variable (ie not const qualified) pointer, this is normally not much of a problem, as that would require dynamic code analysis and in C no code for runtime-checks is generated by the compiler, but for the constant expression above, it could very well cause problems. 对于真正的变量(即非const限定)指针,通常这不是什么大问题,因为这需要动态代码分析,并且在C语言中,编译器不会生成用于运行时检查的代码,但对于上述常量表达式,它很可能会引起问题。

A null pointer is a special pointer value that is known not to point anywhere. 空指针是一种特殊的指针值,已知它不会指向任何地方。 What this means that no other valid pointer, to any other variable or array cell or anything else, will ever compare equal to a null pointer. 这意味着没有任何其他指向任何变量或数组单元或其他任何有效指针的有效指针将与等于空指针的指针进行比较。

The most straightforward way to get a null pointer in your program is by using the predefined constant NULL, which is defined for you by several standard header files, including , , and . 在程序中获取空指针的最直接方法是使用预定义的常量NULL,该常量由几个标准头文件(包括,和)为您定义。 To initialize a pointer to a null pointer, you might use code like 要初始化指向空指针的指针,可以使用如下代码

#include <stdio.h>

int *ip = NULL;

and to test it for a null pointer before inspecting the value pointed to you might use code like 并在检查指向的值之前测试它是否为空指针,可以使用如下代码

if(ip != NULL)
    printf("%d\n", *ip);

It is also possible to refer to the null pointer by using a constant 0, and you will see some code that sets null pointers by simply doing 也可以通过使用常量0来引用空指针,您将看到一些通过简单地设置空指针的代码

char *ip = 0;

NULL represent that the pointer isnt pointing to any address, NULL is a macro for (void *)0 NULL表示指针未指向任何地址,NULL是(void *)0的宏

so you can use (char *)0, it would still point to nothing and it'll be easier to explain the code 因此您可以使用(char *)0,它仍然指向无内容,并且解释代码会更容易

Short answer: Whether you say 简短答案:无论您说

char *p1 = NULL;

or 要么

char *p2 = (char *)0;

or 要么

char *p3 = 0;

they are all pretty much equivalent. 它们几乎相等。 They're all legal, they'll all work, they'll all initialize the pointer variables to null pointer values. 它们全部合法,都可以工作,都将指针变量初始化为空指针值。 The differences between them have to do with style, not correctness. 它们之间的差异与风格有关,与正确性无关。

Whoever wrote the code you saw may just have had a different notion about what constitutes good style. 无论您写的是谁,看到的代码都可能对好的样式构成有不同的看法。

(Now, if you're dealing with pointers of type other than char * , using (char *)0 would be poor, and should at least generate warnings, and under suitably obscure circumstances might actually cause problems.) (现在,如果要处理的char *类型不是char * ,则使用(char *)0会很糟糕,并且至少应该生成警告,并且在适当的晦涩环境下可能会引起问题。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM