从理论上讲,书籍似乎建议在 C 中声明 ADT:
struct some_structure;
typedef some_structure *some_structure_t;
虽然大多数代码使用:
struct some_structure;
typedef some_structure some_structure_t;
我知道这const
不适用于第一种风格。这是真正的图书馆不使用第一种方法的唯一原因吗?任何进一步的通知或建议?
从理论上讲,书籍似乎建议在 C 中声明 ADT:
struct some_structure;
typedef some_structure *some_structure_t;
虽然大多数代码使用:
struct some_structure;
typedef some_structure some_structure_t;
我知道这const
不适用于第一种风格。这是真正的图书馆不使用第一种方法的唯一原因吗?任何进一步的通知或建议?
你的意思是抽象数据类型?如果我从代码片段中的语法错误中抽象出 ;-),我认为,typedef
指针类型是的,因为const
和volatile
.
顺便说一句,您的代码的另一个问题是您选择的名称。_t
作为结尾是为将来在 POSIX 中使用而保留的。
抽象数据类型作为一种有效地对“对象”之类的东西执行操作的方式很有用。
如果可以的话,在 C 语言中,完全避免使用带有结构的“typedef”关键字。它掩盖了真正发生的事情。作为初学者,我建议您struct AStruct
在任何想使用 typedef 的地方显式键入。
从那里你通过声明一个函数来对你的“抽象数据类型”执行一个“动作”,该函数将一个指向“抽象数据类型”(或我喜欢认为的对象)的指针作为第一个参数,然后是普通参数然后。
例如
int some_func( struct AStruct *pObject, int param1, int param2 ) {
if ( ( param1 < 0 ) || ( param2 < 0 ) )
return( 0 );
pObject->val = param1 + param2;
return( 1 );
}
然后使用:
#include <stdio.h>
int main( void ) {
struct AStruct myObject;
if ( some_func( &myObject, 10, 12 ) ) {
printf( "Processed: %d\n", myObject.val );
} else {
printf( "Failed\n" );
}
return( 0 );
}
这取决于其他人的代码将如何处理这些类型。作为你的库的用户,如果我假设 some_structure_t 是一个结构而不是一个指向结构的指针,我可能会做这样的事情:
some_structure_t *p;
p = malloc( sizeof *p);
memcpy( p, &another_p, sizeof *p);
也许这是我作为嵌入式程序员的背景,但我想some_structure_t
在我的代码中了解更多使用它的信息。即使它是真正抽象的类型,并且仅在最终用户代码中用作参数或返回值,您仍然必须在支持该类型的库中处理它。如果我看到下面的代码,我会做双重考虑:
some_structure_t some_function( some_structure_t foo)
{
some_structure_t retval;
retval = malloc( sizeof *retval); // assigning pointer to struct?
retval->member = foo->member; // using -> instead of .?
return retval; // returning potentially large structure on stack?
}
也许这是最大的一个——从一个复制some_structure_t
到另一个。如果是int
a 或 afloat
或 a struct
,则写作foo = bar
会复制。ifsome_structure_t
被定义为一个指向结构的指针,现在foo
和bar
指向同一个对象。也许这就是你想要的,但对我来说这似乎很冒险。
我想知道 MISRA 是否对作为指针的 typedef 有什么要说的。
我用
typedef struct some_s *some_t;
在重要的地方我使用const struct some_s*
or typedef const struct some_s *const_some_t
,但我想这是个人品味的问题。
我曾经使用第一种样式,但我发现我倾向于对访问结构成员所需的间接级别感到困惑,所以我开始为指针类型添加后缀,例如
typedef struct AStruct *AStructRef;
但后来我意识到我实际上是在重新发明 * 运算符,以防止自己因试图隐藏 * 运算符而感到困惑。所以现在我选择第二种风格。