【问题标题】:Trying to use error handling in C尝试在 C 中使用错误处理
【发布时间】:2018-05-14 20:05:39
【问题描述】:

我正在尝试使用以下方法打印错误消息,但在 __VA_ARGS__ 上不断出现错误。函数中使用ERROR_HANDLER()检查sensor_id是否无效:

sensor_value_t datamgr_get_avg(sensor_id_t sensor_id);


#define ERROR_HANDLER(condition,...)    do { \
                      if (condition) { \
                        printf("\nError: in %s - function %s at line %d: %s\n", __FILE__, __func__, __LINE__, __VA_ARGS__); \
                        exit(EXIT_FAILURE); \
                      } \
                    } while(0)

来自comment

我不确定如何使用 ERROR_HANDLER。我必须测试有条件的东西吗?喜欢:

ERROR_HANDLER(sensor_id != NULL, "invalid sensor_id");

【问题讨论】:

  • 你的代码编译得很好。你可能想要!condition 那里。 ERROR_HANDLER(0, "some text"); 为我工作。你得到哪个错误?我得到:Error: in /tmp/Test/Test/main.c - function main at line 25: some text.
  • 我不确定如何使用 ERROR_HANDLER。我必须测试有条件的东西吗?像“ ERROR_HANDLER(sensor_id != NULL", "invalid sensor_id")?

标签: c error-handling


【解决方案1】:

没有检查,但尝试:

sensor_value_t datamgr_get_avg(sensor_id_t sensor_id);


#define ERROR_HANDLER(condition,format,...)    do { \
                      if (condition) { \
                        printf("\nError: in %s - function %s at line %d:", __FILE__, __func__, __LINE__); \
                        printf(format, __VA_ARGS__); \
                        exit(EXIT_FAILURE); \
                      } \
                    } while(0)

注意第二个新参数,它将采用格式字符串。然后在打印错误的前面部分后第二次调用 printf 以使用格式字符串。您可能需要再添加一个 printf 来添加新行。

【讨论】:

    【解决方案2】:

    您现有的宏假定 __VA_ARGS__ 将由单个字符串组成(或者,更确切地说,__VA_ARGS__ 的第一个元素必须是字符串(文字或 char *),并且将评估任何额外的参数但忽略)。这不是很明智。有两种不同的修复方法,具体取决于您的实际需求。

    单字符串参数

    此选项要求提供单个字符串值,而不是可变长度参数列表。这是DevSolar 的解决方案suggested,而我正在打字。

    #define ERROR_HANDLER(condition, msg) \
        do { \
            if (condition) { \
                fprintf(stderr, "\nError: in %s - function %s at line %d: %s\n", \
                        __FILE__, __func__, __LINE__, msg); \
                exit(EXIT_FAILURE); \
            } \
        } while(0)
    

    这有很多先例。只需查看标准 C _Static_assert 声明(又名 static_assert)即可查看示例。

    请注意,我已经改进了打印,使其进入标准错误;那是应该打印错误消息的地方。

    你可以这样使用:

    ERROR_HANDLER(sensor_id == NULL, "Invalid sensor ID");
    

    检查条件,如果结果为真,则打印消息。

    包括格式字符串的参数变量列表

    lachlan 在他们的answer 中概述了基本版本。但是,除了不打印到标准错误(已修复)之外,该解决方案不处理“我只想打印固定字符串”的情况。如果您阅读C #define macro for debug printing,您会发现处理此可选参数的复杂性的讨论。然而,在这种情况下,将格式字符串视为__VA_ARGS__ 之一就足够了:

    #define ERROR_HANDLER(condition, ...) \
        do { \
            if (condition) { \
                fprintf(stderr, "\nError: in %s - function %s at line %d:", \
                        __FILE__, __func__, __LINE__); \
                fprintf(stderr, __VA_ARGS__); \
                exit(EXIT_FAILURE); \
            } \
        } while(0)
    

    这将接受:

    ERROR_HANDLER(sensor_val < MIN_SENSOR_VAL || sensor_val > MAX_SENSOR_VAL,
                  "out of bounds sensor reading %d - should be in range [%d..%d]\n",
                  sensor_val, MIN_SENSOR_VAL, MAX_SENSOR_VAL);
    

    还有:

    ERROR_HANDLER(sensor_id == NULL, "Invalid sensor ID\n");
    

    您可以决定宏是否应确保消息末尾有换行符。

    现在的一个遗留问题是,在多线程程序中,两个fprintf() 语句中的操作将被分别控制,这样就不会发生调用交错,但另一个线程可能会在两个调用之间采用标准错误。您可以使用 POSIX flockfile()funlockfile() 以防止任何交错,但使用可变参数函数来完成这项工作很快就会变得更好,只在宏中留下测试和调用。

    您还可以考虑 assert 宏的逻辑,它也接受一个“条件”,但仅在条件为假时执行错误操作——它断言条件为真但如果为假则采取中止操作.这将有利于经验丰富的程序员熟悉。 (FWIW,我不得不在 5 分钟的宽限期内修改我的答案以反转范围条件;我最初是使用断言模式思维编写代码的。)如果你保持当前的逻辑,也许宏的名称应该变成ERROR_IF(condition, ...)——它更好地解释了它的意图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多