在不安全代码中,将指针赋值为null和0之间有什么区别吗?

8
这可能看起来很奇怪,但在C语言中,(size_t)(void*)0 == 0不能被语言规范保证。编译器允许使用任何值作为null(尽管它们几乎总是使用0)。
在C#中,您可以在不安全代码中将null或(T*)0分配给指针。
有什么区别吗?
(long)(void*)0 == 0是否保证?换句话说:IntPtr.Zero.ToInt64() == 0
MSDN对IntPtr.Zero的解释如下:
"这个字段的值不等同于null。" 如果你想与C代码兼容,那么这就有了很多意义-如果它不能转换为C空指针,那么Interop就毫无价值。但我想知道IntPtr.Zero.ToInt64() == 0是否可能,即使在内部IntPtr.Zero是其他值(CLR可能会在强制转换操作中将null转换为0)。
这不是此问题的重复。
2个回答

5
您可以避免这个问题:
char* foo = (char*)(void*)0;
char* bar = default(char*); // <======= the one to look at
Console.WriteLine(foo == bar); // writes True

所以它们是相同的,但使用 "default" 可以避免将任何假设或恶意转换嵌入到代码中。对上面的内容进行反汇编,唯一的区别是有符号 / 无符号 - 都以 4 字节常量(i4 / u4)开头,然后转换为本地整数(i / u)(// 注释属于我):
.maxstack 2
.locals init (
    [0] char* foo,
    [1] char* bar)
L_0000: ldc.i4.0 // (char*)(void*)0;
L_0001: conv.i 
L_0002: stloc.0 // foo=
L_0003: ldc.i4.0 // default(char*);
L_0004: conv.u 
L_0005: stloc.1 // bar=
L_0006: ldloc.0 
L_0007: ldloc.1 
L_0008: ceq  // foo == bar
L_000a: call void [mscorlib]System.Console::WriteLine(bool)

啊,我忘了默认值也适用于指针。这是一个不错的解决方案。 - Eloff

0
在 C 语言中,NULL 的定义是与体系结构有关的。虽然大多数体系结构使用 0,但有些不使用。因此,在 C 语言中不能假定 NULL == 0
在 C# 中它的工作方式尚不清楚,但我建议您坚持使用 C# 中指定 NULL 的标准方法,而不是将其转换为 0。

在C#中,指针的标准空值指定方式是什么?我看到过两种用法,将0强制转换似乎更常见。我喜欢null,因为它更易读,但使用哪种取决于它们是否等效的答案。 - Eloff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接