【问题标题】:How to make static array point to NULL如何使静态数组指向NULL
【发布时间】:2020-09-17 13:30:31
【问题描述】:

由于我无法删除数组并且我想清理内存,因此是否有可能使结构的静态数组指向 NULL?

假设我们有以下代码:

struct_x defaultStructX[6];
struct_x requiredStructX [6];
gettingDefaultX(defaultStructX, 6);         

                for (uint8_t i = 0; i <6; i++)
                {
                     setStructX(requiredStructX[i].index, requiredStructX[i].icirate, requiredStructX[i].icis, requiredStructX[i].iei);

                    //error handle case
                    if (status == STATUS_SUCCESS)
                    {
                        writeResponse.writeStatus = status_ok; /*This is another struct not important at this point*/
                    } else
                    {
                        errorHandleQciFlowMeter(defaultStructX, 6);
                        writeResponse.writeStatus = status_nok; 
                        break;
                    }
                }

/*here I want to write code line to clean the defaultStructX from memory. Is it possible? I have tried *defaultStructX[i]= NULL and ##((void*)defaultQciFlowMeter) = NULL; ## and many other methods but it didn't work*/

【问题讨论】:

  • 数组不是指针。如果你有一个数组类型的变量,你不能手动改变它的生命周期。
  • 为什么要“清理内存”,这意味着什么?

标签: arrays c optimization struct null


【解决方案1】:

由于我无法删除数组并且我想清理内存,因此是否有可能使静态结构数组指向 NULL?

没有。数组不是指针,特定数组指针的元素也不是指针。指针值不能分配给数组本身或元素,特别是,NULL 不能分配给它们。

你可以覆盖数组占用的内存,比如说,

memset(defaultStructX, 0, sizeof(defaultStructX));

这将替换以前存储在其中的数据,* 如果这些数据很敏感,这可能很有用。然后,应用程序需要为数组元素分配新的有效值,然后再再次使用它们。

但是,无论如何,您都无法释放具有静态存储持续时间的对象的内存,该对象是在文件范围内、在所有函数之外或在函数内使用 static 限定符声明的任何对象。静态存储持续时间的全部意义在于对象的生命周期是程序运行的整个持续时间。如果您希望能够释放内存,那么您应该为您的数组动态分配空间,或者,如果它适用于您的特定应用程序,则自动分配空间(作为精心选择的函数的局部变量)。


* 原则上。正如@chux 在 cmets 中指出的那样,编译器可能会选择优化这样的覆盖,如果它可以确定从未读取过归零的数据,它可能会这样做。如果这是一个问题,那么最好的缓解措施可能是声明数组volatile

【讨论】:

  • 我知道它非常常见,但严格来说,如果结构包含任何指针,则此 memset 方法可能会导致 UB,随后将其与 NULL 进行比较,因为 C 没有指定空指针是在内存中由零值字节表示(某些平台确实使用不同的值)。在运行时清零结构数组的安全方法是使用memset(defaultStructX, default, sizeof defaultStructX / sizeof default);,其中defaultstruct_x 的静态分配副本。
  • 确实如此,@KonradRudolph,但在这里无关紧要。在这种情况下,memset() 的目的是销毁数据,假设它可能是敏感的,因此不能保留在内存中。这并不意味着让对象处于一致状态。如果希望重用它们,那么设置新的有效值将是应用程序的责任。
  • @KonradRudolph memset() [idea]()stackoverflow.com/questions/63939174/… 仅在 sizeof (struct_x) 为 1 或 struct_x 中的所有字节都相同时才有效。
  • @John, memset() 不足以将敏感数据归零,因为 memset() 可能会被优化掉。通过volatile char * 进行循环归零是一种替代方法。
  • 我经常看到应用程序特定的功能解决方案,但使用volatile 可以避免被优化。 e.g.
【解决方案2】:
struct_x defaultStructX[6];
struct_x requiredStructX [6];

通过上述语句,您为两个结构数组保留了内存。此内存将在程序的整个生命周期内一直分配给您,并且在您的程序退出之前无法解除分配。

但是,您要在此内存中存储的内容完全在您的控制之下。您对“从内存中清除”的定义是什么?

您是否有一些要从内存中删除的敏感数据?您始终可以通过以下方式将memset 归零(或任何其他值):

memset(defaultStructX, 0x00, sizeof(defaultStructX));

您想物理地取消分配内存吗?如果您想控制内存块的分配和释放,您应该使用mallocfree

编辑:显然 memset() 解决方案可以是derailed by compiler optimizationsHere 是 SEI CERT C 页面中对此问题的有用描述。

【讨论】:

  • "你总是可以使用 memset 将它们设置为零(或任何其他值)..." --> no.
  • @chux-ReinstateMonica 感谢您的指出 - 添加了有关此问题的说明。
【解决方案3】:

您不能手动取消分配未使用 malloccallocrealloc 分配的任何内容。如果您在文件范围内(在任何函数之外)或使用 static 关键字声明了数组,那么它们的内存在程序终止之前不会被释放。否则,当声明它们的函数退出时,它们的内存将被释放。

您可以用零或其他一些“非值”值覆盖当前未使用的元素,但您无法释放它们占用的内存。

数组不是指针。数组类型的表达式会根据需要转换为指针,但数组对象本身并不是指针。

【讨论】:

    【解决方案4】:

    由于我无法删除数组并且我想清理内存,因此是否有可能使结构的静态数组指向 NULL?

    没有。数组不指向。数组可以被清除。

    我想编写代码行来清除内存中的 defaultStructX。

    只需为其分配零。

    memset() 如果编译器发现随后没有读取数据,则可以进行优化。

    替代方案:使用带有指向易失性数据的指针的循环,以避免循环被优化。

    volatile unsigned char *vp = defaultStructX;
    for (size_t i = 0; i<sizeof defaultStructX; i++ {
      vp[i] = 0;
    }
    

    【讨论】:

      【解决方案5】:

      嗯...一方面我喜欢 John Bollinger 提供的详细答案,我相信他为您的用例给出了正确的答案...但是...

      有一种方法可以使静态分配的数组看起来指向 NULL。

      显然您不能将NULL 分配给数组。但是,您可以将静态分配的“数组”看起来隐藏在指针后面,使其指向NULL

      它可能看起来像这样:

      #define STRUCT_X_ARRAY_LENGTH 6
      struct_x defaultStructX___[STRUCT_X_ARRAY_LENGTH];
      struct_x requiredStructX___[STRUCT_X_ARRAY_LENGTH];
      struct_x * defaultStructX = defaultStructX___;
      struct_x * requiredStructX = requiredStructX___;
      gettingDefaultX(defaultStructX, STRUCT_X_ARRAY_LENGTH);         
      

      现在您可以使用以下方法将(不再)“数组”设置为 NULL

      defaultStructX = NULL;
      requiredStructX = NULL;
      

      您还可以使用以下方法重置状态(将内存清零并重新分配正确的内存地址):

      defaultStructX = defaultStructX___;
      requiredStructX = requiredStructX___;
      memset(defaultStructX___, 0 , sizeof(defaultStructX___));
      memset(defaultStructX___, 0 , sizeof(requiredStructX___));
      

      这并不适合您的用例,但它是一种足够好的技术,其他人可能想知道它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 2021-01-24
        • 2014-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多