【问题标题】:C - how to check whether all required fields of a structure are filled? (most elegant method)C - 如何检查结构的所有必填字段是否都已填写? (最优雅的方法)
【发布时间】:2009-11-20 11:36:14
【问题描述】:

我有一个函数,它有一个指向某个结构的指针作为它的参数。如何在此函数中检查结构的所有必填字段是否在函数调用之前已填充?

示例:

//lib.c
void f(X_type *x)
{
  ...
}

//user.c
main(){
X_type object;
object.name = "I am X";
object.ID = 1;
...
f(X_type &object);
}

【问题讨论】:

  • 能给出结构的定义吗?
  • 没关系——它只是一个结构
  • 如何区分已填字段和未填字段?未填充为零/NULL?
  • 写一个构造函数。哎呀。 :)
  • 一个未初始化的结构可能包含,例如,int 字段中的值 42。你无法区分垃圾 42 和好的 42

标签: c function structure


【解决方案1】:

创建一个将所有字段作为参数的初始化函数(就好像它是一个对象构造函数一样)并使用它而不是一一设置字段。

当然,这不会阻止任何人继续以错误的方式进行操作,但是如果您保持使用该功能的纪律,那么在不注意的情况下留下未初始化的某些字段将会更加困难。如果您更改结构的字段(以及相应的函数),编译器会在您忘记更新的地方抱怨参数不匹配。

您可以走得更远一些(但仅使用纯 C 就不会更多)使用预处理器和包含执行一些技巧来强制数据封装,但这有点麻烦。任何关于 C 语言的 OOP 书籍都可以帮助您解决这个问题,但我不知道是否值得付出努力。

【讨论】:

  • 使用预处理器和包含执行一些技巧来强制数据封装 --- 你能解释一下吗?带有 C 的 OOP 将帮助您解决该问题 --- 请问哪一个?我还没有听说过 C 和 OOP(或者你的意思是 C++?)。
  • 我的意思是普通的 C,但这样做不是很愉快……例如,看看 Glib 文档,或者这本书 planetpdf.com/codecuts/pdfs/ooc.pdf
  • 看看这个例子:en.wikipedia.org/wiki/Opaque_pointer#C 这种方法的坏处是你一定会使用动态内存,但我认为有一种方法可以绕过它,通过定义和未定义的东西...让我进一步看看。
【解决方案2】:

valgrind 在您的系统上可用吗?如果您通过它运行程序,它将自动检测任何未初始化变量的使用。它还可以捕获很多其他问题(例如使用已经释放的内存)。这不会成为您程序的永久功能,但它非常适合调试。

我会将它与前面提到的断言和增加的编译器警告结合起来。这就是你所能做的——问题是初始化内存和未初始化内存之间没有区别。对于机器来说,它们都只是值。

【讨论】:

    【解决方案3】:

    使用断言(来自 assert.h)来检查您的函数所需的先决条件。由您决定什么是结构字段的有效值或无效值。

    示例:

    assert( NULL != object);
    assert( NULL != object->name);
    

    【讨论】:

    • 我必须检查一个结构是否被填满。
    • @Sebastiaan:检查一段内存是否已初始化很棘手。我没有看到任何灵丹妙药。我认为唯一可行的事情是检查先决条件。
    • 不!它不起作用。我不想检查字段的值。我必须检查它们是否已设置(或其中一些取决于第一个参数)。
    • @Norma:除非你对每个字段都有一些约定,否则它是有效值,什么不是,你不能。
    • 您可以打开编译器警告并捕获大量(但不是全部)未初始化变量的使用。
    【解决方案4】:

    向结构中添加另一个成员以指示其余成员是否已填充(并将其初始化为“false”)。然后检查那个新成员。

    struct whatever {
      int datagood;
      /* more members; */
    };
    
    struct whatever bar;
    bar.datagood = 0;
    
    foo(&bar); /* foo() will see datagood == 0 */
    
    /* bar.a = 42; */
    /* bar.b = 24; */
    bar.datagood = 1;
    
    foo(&bar); /* foo() will see datagood == 1 */
    

    【讨论】:

    • 什么可以阻止您偶尔初始化仅 datagood 字段?
    • 看起来这不是对问题预期的正确解释。但是+1,pmg 的建议对于一些惰性初始化是好的,例如: if (!foo->InitializedBefore) { /* ... */ foo->InitializedBefore = 1; }
    【解决方案5】:

    我认为 C 本身没有解决方案。正如其他人所建议的,您可以使用 valgrind,但这是另一回事。我总是 memset() 结构:

    memset(&object, 0, sizeof(struct mystruct));
    

    struct mystruct *p = calloc(1, sizeof(struct mystruct));
    

    然后你可以对照0检查成员。我相信这是一个好习惯。

    【讨论】:

      【解决方案6】:

      通过静态分析。 Parasoft C++test 有 BD-PB-NOTINIT(避免使用未初始化的数据)流分析规则。

      【讨论】:

        【解决方案7】:

        最好的办法是编写一个函数来手动验证结构的内容并返回 True/False(无论您如何定义它),这样您就可以在任何使用该结构的地方轻松使用该方法。

        【讨论】:

          【解决方案8】:

          这通常可以通过仔细的编程来解决,但如果你必须确定,这里有一个矫枉过正的想法:

          • 添加校验和/CRC 字段。
          • 添加成员更新功能,同时修改校验和字段。
          • 使用时,使用另一个函数将字段的校验和与校验和字段的校验和进行比较。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-11-26
            • 1970-01-01
            • 1970-01-01
            • 2010-09-28
            • 1970-01-01
            • 2017-07-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多