为什么在 c 中对结构使用下划线?

why to use an underscore for a struct in c?

在下面的源代码中,有人可以解释一下合理的(为什么typedef结构_lwm2m_object_t具有新名称lwm2m_object_t是好的编程习惯?它所做的只是去掉下划线?为什么首先使用下划线?

typedef struct _lwm2m_object_t lwm2m_object_t;

typedef uint8_t (*lwm2m_read_callback_t) (lwm2m_uri_t * uriP, char ** bufferP, int * lengthP, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_write_callback_t) (lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_execute_callback_t) (lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_create_callback_t) (lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_delete_callback_t) (uint16_t id, lwm2m_object_t * objectP);
typedef void (*lwm2m_close_callback_t) (lwm2m_object_t * objectP);


struct _lwm2m_object_t
{
    uint16_t                 objID;
    lwm2m_list_t *           instanceList;
    lwm2m_read_callback_t    readFunc;
    lwm2m_write_callback_t   writeFunc;
    lwm2m_execute_callback_t executeFunc;
    lwm2m_create_callback_t  createFunc;
    lwm2m_delete_callback_t  deleteFunc;
    lwm2m_close_callback_t   closeFunc;
    void *                   userData;
};

每个人或每个团队出于不同的目的使用前导下划线。在 answer, specifically the paragraph that is dedicated to .

中阅读更多内容

我经常看到这个:

typedef struct lwm2m_object lwm2m_object_t;

其中将向结构的名称附加一个 _t,向 reader 表示这是一个 typedef'ef 名称。

typedef struct _lwm2m_object_t lwm2m_object_t;意味着当你想引用struct类型时不需要写更冗长的struct _lwm2m_object_t,但是你可以使用lwm2m_object_t 直接代替。它节省了输入,并且可以使源代码更清晰。

在实际的 struct 名称前加上单个 _ 是多年来形成的惯例。许多人使用 _t 作为后缀来表示 类型 .

但有几点需要注意:

  1. 永远不要使用 下划线,因为形式上这样做的行为是未定义的。

  2. 类型不要以单个下划线后跟大写字母开头。同样,此类名称是保留的。

  3. POSIX 明确禁止您以 _t 结束您自己的类型,但请注意 standard C 允许它。

许多有经验的 C 程序员发现 (3) 可恶并忽略它。 (我愿意。)

实际上如果你使用

typedef struct lwm2m_object_t lwm2m_object_t;

struct lwm2m_object_t {
//
}

C 仍然允许它。这是因为结构名称和 typedef 标识符具有不同的命名空间。请参阅 Why doesn't ANSI C have namespaces? 了解有关 C 中命名空间的信息。

但是,许多专业用户会避免这种情况,并对结构和类型定义使用不同的名称。 MISRA1 也不允许这样做。

Rule 5.6 (advisory): No identifier in one name space should have the same spelling as an identifier in another name space, with the exception of structure member and union member names. [MISRA C 2004]

下划线的使用只是一些人遵循的约定。您可以遵循其他约定,例如

typedef struct sTag_lwm2m_object_t lwm2m_object_t;

struct sTag_lwm2m_object_t {
//
}

1 https://en.wikipedia.org/wiki/MISRA_C

就其本身而言,前导下划线没有内在含义,它只是为标签名称与 typedef 名称创建了一个不同的标识符。您可以使用

获得相同的结果
typedef struct foo fooType;

标签名与普通标识符占用不同的命名空间,所以可以这样写

typedef struct foo foo;

有些人认为这令人困惑。我不知道 - 标签名称因 struct(或 unionenum)关键字的存在而被消除歧义。

您应该在您的标识符中使用前导下划线 - 带有两个前导下划线或一个前导下划线后跟一个大写字母的标识符始终保留用于任何用途的实施,而具有单个前导下划线的标识符保留在普通和标记名称空间中。

您可以使用尾部下划线来达到同样的效果

typedef struct foo_ foo;

让大家满意