【问题标题】:how to set pointer to a memory to NULL using memset?如何使用 memset 将指向内存的指针设置为 NULL?
【发布时间】:2008-12-29 22:18:10
【问题描述】:

我有一个结构

typedef struct my_s {

   int x;
   ...
} my_T;

my_t * p_my_t;

我想将p_my_t 的地址设置为NULL,到目前为止,我尝试这样做:

memset (&p_my_t, 0, sizeof(my_t*))

不过,这对我来说并不合适。这样做的正确方法是什么?


修改问题 - 提出一个更复杂的问题

这是我想要做的:

  • 两个进程,A 和 B
  • malloc p_my_t in A, B有N个线程,可以访问
  • 开始在 A 中删除,但我不能简单地释放它,因为 B 中的线程可能仍在使用它。
  • 所以我调用了一个函数,将 p_my_t 的地址传递给 B 以将其地址设置为 B 中的 NULL,这样 B 中的其他线程就不能再使用了
  • 从 B 回调后,我在 A 中释放内存

注意:没有标准的方法可以通过进程之间的共享内存来管理内存分配。您将不得不对正在发生的事情做一些相当仔细的思考。

【问题讨论】:

  • 你是想把p_my_t设置为NULL,还是想把p_my_t的地址设置为NULL?
  • 设置p_my_t的地址为NULL
  • @dave:不能将 p_my_t 的地址设置为 NULL(p_my_t 是内存位置的名称);您可以将 p_my_t 的值设置为 NULL,因此它不会指向任何地方。
  • @dave:另外,你不应该使用 _t 作为变量名的后缀。将它用于类型并不是一个特别好的主意(POSIX 保留以 _t 结尾的类型名称以供实现使用),但是以 _t 结尾的变量会让人非常困惑。

标签: c++ null pointers memset


【解决方案1】:

不要使用memset 来初始化空指针,因为这会将内存设置为所有位为零,这不能保证是空指针的表示,只需这样做:

p_my_t = NULL;

或等价物:

p_my_t = 0;

【讨论】:

  • 谁推荐的? 0 不像 NULL 那样“富有表现力”,i = NULL 清楚地表明 i 是一个指针,i = 0 不是。
  • 在 C++ 中,NULL 被定义为 0,因此“i = NULL 表明 i 是一个指针”不是由编译器强制执行的。 C++0x 有 nullptr,这确实是强制的。
  • 关键是它让阅读您的代码的人清楚。
  • 最好使用NULL。它更具可读性,并且在 NULL 的定义发生变化的情况下,您的代码不会中断。
  • 该标准保证将 0 转换为空指针的正确位模式。它没有说明 NULL。 NULL 只是为了向后兼容 C 代码。
【解决方案2】:

你到底想做什么? p_my_t 已经是一个指针,但你还没有为它分配内存。如果要将指针设置为 NULL,只需执行

p_my_t = NULL;

尝试取消引用此指针将导致分段错误(或 Windows 上的访问冲突)。

一旦指针实际指向某个东西(例如,通过malloc() 或通过为其分配struct my_T 的地址),那么您可以正确地memset() 它:

memset(p_my_t, 0, sizeof(struct my_T));

这会将整个结构清零,将所有字段设置为零。

【讨论】:

  • 谢谢,这里添加cmets有限制,请看我的“回答贴”
【解决方案3】:

将指针设置为 null 的推荐代码是分配 0(零)。 Bjarne Stroustrup does it :) 无论如何,它与 NULL 一样具有表现力,并且不依赖于宏定义。

请注意,NULL 不是关键字,它不是保留的,虽然重新定义会令人困惑,但没有什么说你不应该(除了风格)。一位同事经常开玩笑说在某些标头中将 NULL 定义为不同于 0 的值,只是为了看看其他人的代码如何表现。

在即将发布的标准中,将有一个更具表现力的 nullptr 关键字来标识空指针。

【讨论】:

  • 实际上,它有效地禁止重新定义NULL。你不允许#undef NULL,因为一旦你包含一个定义它的标准头,它就会被保留。
  • NULL 更好!下一个 c++ 标准将有一个新对象 nullptr。使用 0(将 int 转换为指针)时存在问题,nullptr 将解决它们。在 gcc 中,NULL 被定义为 __null。一旦 nullptr 成为标准,将 NULL 从 0 更改为 nullptr;所有的好处都没有改变。
【解决方案4】:

我想也许你想要

extern void set_t_pointer_to_null(my_T *pp);

然后打电话

set_t_pointer_to_null(&p_my_t);

在哪里

void set_t_pointer_to_null(my_T *pp) { *pp = NULL; }

我不确定是否值得定义一个函数来执行此操作,但我认为这回答了您要提出的问题。

【讨论】:

    【解决方案5】:

    谢谢,这是我正在尝试做的事情

    • 两个进程,A 和 B
    • malloc p_my_t in A, B有N个线程,可以访问
    • 开始在 A 中删除,但我不能简单地释放它,因为 B 中的线程可能仍在使用。
    • 所以我调用了一个函数,将 p_my_t 的地址传递给 B 以将其地址在 B 中设置为 NULL,这样 B 中的其他线程就不能再使用了
    • 从 B 回调后,我在 A 中释放内存

    【讨论】:

    • 您可能应该将此信息添加到您的问题中,或改写它 - 但它听起来不像您在此处描述的那样正确。除非指针指向共享内存,否则如何跨进程共享?
    • 我同意这与原始问题不同。您应该将此作为一个单独的问题提出,因为您实际提出的问题的答案只是 p_my_t = NULL;
    • @dave:这两个进程如何共享内存?这与您最初提出的问题大不相同。
    【解决方案6】:

    根据您的回复(在这篇文章的其他地方)说明:

    谢谢,这是我正在尝试做的事情

    • 两个进程,A 和 B
    • malloc p_my_t在A,B有N个线程,可以访问
    • 开始在 A 中删除,但我不能简单地释放它,因为 B 中的线程可能仍在使用。
    • 所以我调用了一个函数,将p_my_t 的地址传递给 B 以在 B 中将其地址设置为 NULL,这样 B 中的其他线程就不能再使用了
    • 从 B 回调后,我在 A 中释放内存

    您需要的是所有线程和进程之间的某种形式的同步。我不确定您如何在进程之间共享此对象,但我怀疑您正在使用共享内存。

    通常我会推荐使用共享指针类(例如 Boost 的 shared_ptr 类),但我不确定在这种情况下它的效果如何。您可能需要考虑调整您的类,以便它跟踪自己的引用并可以与 Boost intrusive_ptr 类一起使用。

    这样,进程 A 可以简单地忘记对象,当进程 B 完成时,my_T 的实例将知道没有更多的引用并自行清理。

    my_T 在内部添加或删除引用时,同步将在这里发挥作用(因此您不会遇到令人讨厌的竞争条件,它认为它应该自行清理但实际上仍在使用中)。

    另一种更“kluge”感觉的方法是给my_T的每个实例一个“is-valid”标志,以便所有使用它的进程/线程都知道是否继续这样做。

    有关 Boost 各种指针类的更多详细信息,请查看their documentation

    【讨论】:

    【解决方案7】:

    通过阅读您的多线程 cmets,我应该说没有 安全的代码序列来完成您的任务。您将不得不退后一步,重新检查您的算法。

    【讨论】:

      【解决方案8】:

      如果我做对了,memset 将无法解决您的问题。如果 A 和 B 是独立的进程,那么进程 A 中的 p_my_t 将不同于进程 B 中的 p_my_t。您只是不能在不同进程之间传递指针。我建议你使用某种 IPC 机制来同步你的两个进程(例如消息队列),并且只使用 p_my_t = NULL 而不是 memset。

      【讨论】:

        【解决方案9】:

        根据您的更新,在我看来,您真正想做的是保护对资源的访问,这意味着您应该使用进程之间共享的读/写锁来保护该资源的 ptr,并在使用前测试ptr。

        • 在共享内存中分配结构。
        • 将 ptr 分配给共享内存中的结构。
        • 使用读/写锁保护对结构的 ptr 的访问。
        • 在初始化 ptr 和结构或使其无效时,进程 A 应获取对 ptr 的 WRITE 锁。
        • 进程 B 应获取指向 ptr 的 READ 锁,并在使用结构之前测试 ptr 是否有效

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-24
          • 2013-07-30
          • 2014-02-03
          • 1970-01-01
          相关资源
          最近更新 更多