Null与ZeroMemory的区别

6

将对象设置为NULL和使用ZeroMemory有什么区别呢?

我听说在WinAPI(主要是C语言)中,一个人应该对C对象使用ZeroMemory。我来自C#的背景,这似乎是C ++程序员真正需要知道的。

我发现在DirectX API中,无论你是否使用ZeroMemory,应用程序仍然可以运行,但有些示例使用ZeroMemory,有些则不使用。

能否有人澄清这些问题呢?


这篇文章很有帮助:http://blogs.msdn.com/b/oldnewthing/archive/2005/06/28/433341.aspx - David Heffernan
可能是重复的问题:memset()或值初始化哪一个用于将结构体清零? - Sheng Jiang 蒋晟
8个回答

5

这两件事情完全不同。 ZeroMemory宏 可以将一块内存全部填充为0。而将指针设置为NULL,仅仅只是让它指向了空地址。

例如,假设您有一个指向类型为“Type”的对象o的指针p

struct Type
{
    int i;
    float f;
    bool b;
};
Type o;
Type* p = &o;

// In memory that will be something like this:
// "o" internals = [010101010001010010110010010010100011001001010000011...]
// "p" address = 0x00830748
//(number of bits and hex adress is just example)

如果您对其使用 ZeroMemory 函数:

ZeroMemory(&o, sizeof(o));
// ---- or -----
ZeroMemory(p, sizeof(o));

// In memory we will have:
// "o" internals = [000000000000000000000000000000000000000000000000000...]
// "p" address = 0x00830748

现在,o 内部的所有变量都具有零值:

cout << o.i; // 0
cout << o.f; // 0.0f
cout << o.b; // false

cout << p->i; // 0
cout << p->f; // 0.0f
cout << p->b; // false

如果你将指针置为NULL

p = NULL;
// In memory we now have:
// "o" internals = [010101010001010010110010010010100011001001010000011...]
// "p" address = 0x00000000

如果现在解引用p,你将获得未定义的行为:
int a = p->i; // Access voilation reading location 0x00000000

如果你将对象置为NULL 如果Type没有重载运算符=(),则编译不会通过。

o = NULL; // error C2679: binary '=' : no operator found 
          // which takes a right-hand operand of type 'int' 
          // (or there is no acceptable conversion)

将其应用于DirectX

当您使用DirectX时,必须填写一些结构体以将它们传递给API函数。这就是魔法所在。您可以使用ZeroMemory将其清零为默认值0,然后只需填写所需的值,简化代码并避免出现奇怪值的错误(如果创建对象并且不设置某些成员变量,则其将包含垃圾值)。


哇!非常详细的回答!当对象是POD时,一个人是否应该在设置为NULL之前总是使用ZeroMemory - Mark Russ
@Mark 为什么你总是喜欢清零操作?如果你想要清零内存,可以调用 ZeroMemory 函数(或者使用 memset(..., 0, ...)),否则就不需要。 - David Heffernan
@Mark Russ 不,你不应该总是这样做。但如果你需要这样做,那就去做吧 =) - Ivan Aksamentov - Drop

5

ZeroMemory函数将一块内存区域清零。

将指针设置为NULL只是使指针指向空,与用0填充指针所指向的内存不同(例如,您仍然可以通过该指针访问该内存)。

在对该对象进行任何有用的操作之前,很可能需要用更有意义的内容替换这些零 - 这就是为什么使用ZeroMemory或不使用都可以正常工作的原因。

在这种情况下使用ZeroMemory的原因是,您可能会轻松地找到对未初始化的对象进行操作的情况(例如,Visual Studio正在用 0x0c0c0c0c /*或类似*/填充未初始化的内存,因此在调试期间遇到此模式时,您就知道对象尚未初始化)。


啊!这真的很有道理!现在我知道为什么一个人应该使用ZeroMemory的好理由了。 - Mark Russ
完全确认了我的想法,描述得非常完美。 - saeed
2
请注意,如果您出于安全原因(如密码/密钥)而进行清零操作,则应使用SecureZeroMemory(),因为某些情况下常规的ZeroMemory可能会被优化掉。 - Paul Rubel

3
在C和C++中,“对象”不能被设置为NULL。可以将指向对象的指针设置为NULL,这意味着指针本身指向空(“null对象”)。
这与将对象的内容设置为“所有位都为零”不同,后者是ZeroMemory()所做的。您通常只能对structs执行此操作,而不能对完整的C++对象执行此操作,否则可能会出现非常严重的反应。

2

ZeroMemory()函数将内存设置为0,即清空该内存。将一个对象(指向该对象的指针)设置为NULL意味着该对象的基地址被初始化为0。


0

从良好的实践角度来看,我建议你两者都使用。

// Consider mystuff as being a pointer to an object.
ZeroMemory(mystuff); // Makes this part of memory to be clean
mystuff = NULL; // Makes this pointer point to null so you dont access a 0-memory section.

在使用DirectX API时,您可以使用malloc分配内存,在这种情况下,调用ZeroMemory();将无法按预期工作。对于由malloc();分配的内存,您应该使用free();进行调用。在处理指针时,我通常在释放后立即将它们设置为NULL,不知道这是否是一个好习惯。


0

ZeroMemory 用于将较大的内存块设置为零。它不应该用于那些不是“POD”(普通旧数据)的对象,也就是说,如果您的对象具有构造函数或虚拟方法,则不应使用它。

NULL 用于指示指针指向“无”。

从技术上讲,ZeroMemory(pointer, sizeof(pointer));pointer = NULL; 将得到相同的结果,但是 a) 后者更清晰,b) 执行后者很可能更快。


0

清零内存将一部分内存设置为零,对于更常见的用于将大向量设置为零的对象来说是有害的,但它可以快速工作。而空指针则更常用于当您想要一个指针指向空时,其使用取决于您的程序指针或设置内存值。


0

NULL 将算术类型变量或(数据或函数)指针变量设置为0。自 C++11 开始,对于指针而言,nullptr 也具有相同的作用,并且出于正确和惯用的原因建议使用它。

然而,ZeroMemorystructclass 的内容逐字节设置为0。

ZeroMemory(或 RtlZeroMemory)是将第二个参数设置为 0memset 的预处理器定义。

void* memset(void* dest, int ch, std::size_t count);

#define ZeroMemory(dest,count) memset((dest),0,(count))

你可以说ZeroMemory是将memset设置为0
示例:
D3D11_BUFFER_DESC indexBuffDesc;
ZeroMemory(&indexBuffDesc, sizeof(indexBuffDesc));
// or:
memset(&indexBuffDesc,0,sizeof(indexBuffDesc));

ZeroMemory 就像格式化驱动器(不是快速格式化)。

NULL/nullptr 想象成擦除一个充满宝藏的强力金库门,这样你将永远无法进入。而 ZeroMemory 则是摧毁强力金库内所有宝藏和其他物品的内容;你可以进入其中,但里面什么也没有。这就是我对它们的看法。


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