用例#ifdef _MAIN_

Uses cases #ifdef _MAIN_

使用时的主要目标是什么: #ifdef _MAIN_ 在 c 程序的头文件中。

这是一个例子:

#ifndef _INTDSPMNG_H_
#define _INTDSPMNG_H_

#include <pthread.h>

typedef struct dspList_t 
{
    char mesfct[CL_MESFCT+1]; 
    char processus[CL_NOMLOG+1]; 
    char requete_json[CL_MSJSON+1]; 
    char reponse_json[CL_MSJSON+1]; 
    int actif; 
}dspList_t;

/* Gestion des erreurs */
#define CV_DSPMNG_OK    0      
#define CV_DSPMNG_ERROR 1
#define DELAI_REVEIL_DSPMNG     
#ifdef _MAIN_
    dspList_t *gDspmngTab = NULL;
    int nb_config_dspmng = 0;  
    PARAM_COM_WEBSRV ParamCom;  
#else
    extern dspList_t *gDspmngTab;         
    extern int nb_config_dspmng;    
    extern PARAM_COM_WEBSRV ParamCom;   
#endif

#endif

说明项目结构错误

    extern dspList_t *gDspmngTab;  
    extern int nb_config_dspmng;     
    extern PARAM_COM_WEBSRV ParamCom;  

这些行应该在头文件中。那么所有使用该对象的 .c 文件都应该包含它。只有一个源文件应该定义实际对象。

IMO 代码的作者需要声明,但从未听说过头文件。所以他决定这样做#ifdef“黑魔法”

习惯做法是在header文件中声明一个object(或函数),并在一个源文件中定义它。例如,给定一个名为 foo 的 object 在名为 bar.c 的文件中定义为 MyType foo = 0;,header 文件 bar.h 将声明 MyType foo;.然后每个需要 foo 的源文件将使用 #include "bar.h" 来获取它的声明。

您所询问的代码的作者显然决定将定义和声明放在一起。他们的 header 文件 intdspmng.h (根据包含防护的名称推测)可以包含在源文件中,并且通常会声明标识符。但是,当他们将其包含在 main.c 或他们指定为主文件的任何内容中时,他们首先定义 _MAIN_,可能使用 #define _MAIN_#define _MAIN_ 1。然后,当它们包含 intdspmng.h 时,它会定义标识符而不是仅仅声明它们。

换句话说,那个人可能想“我想把这些东西的声明和定义放在一起,因为这样更容易编辑它们,也更容易看到定义和声明之间的关联。因此,我将编写可以放入 header 文件但仅定义主文件中内容的代码。”

这可能并非完全不合理。然而,他们犯了一个错误。声明的一个目的是检查它们是否与定义相匹配。如果在定义标识符的源文件中,我们还包括声明它们的 header,那么编译器会同时看到声明和定义,如果它们发生冲突,它将报告警告或错误,就像印刷发生错误或类型在一个地方更改,但在另一个地方没有更改。

这可以通过始终包含声明来补救,而仅当 _MAIN_ 的定义要求时才包含定义:

extern dspList_t *gDspmngTab;         
extern int nb_config_dspmng;    
extern PARAM_COM_WEBSRV ParamCom;
#ifdef _MAIN_
    dspList_t *gDspmngTab = NULL;
    int nb_config_dspmng = 0;  
    PARAM_COM_WEBSRV ParamCom;  
#endif

虽然这弥补了这个不足,但我仍然不会说我推荐这种方法。

另一个问题是,根据 C 标准,以下划线开头后跟大写字母或另一个下划线的标识符是保留的。在一般程序代码中应避免使用它们,尽管编译器和“系统”库可能会使用它们。所以_MAIN_应该改成别的,比如DefineMainObjects.