C和C++类型(typedef)的区别

3
我将尝试理解C和C++之间的区别,通过重新设计我在数据库课程期间使用C语言编写的项目(创建自己的数据库系统)的API。现在我正在尝试重新设计该项目的API,以便它也可以用于使用C++语言编写的应用程序。
我对typedef struct、enum、float等内容感到困惑。
我的C头文件代码如下:
typedef enum { FALSE = 0, TRUE } bool_t;
typedef float  real;
...
typedef  struct _hf_record_identification {
    int pagenum;
    int recnum;
} RECID;

我在阅读了几篇有关的参考文献后得出结论,可以用C++表示为:

enum bool_t {FALSE = 0, TRUE };
float real;
...
struct _hf_record_identification RECID {
    int pagenum;
    int recnum;
} ;

我的问题是:C语言中的typedef和C++语言中的typedef有什么主要区别?在C++中使用typedef对我来说并不麻烦。我对C语言中的typedef感到困惑。对于typedef float real这种情况,我是否使用得正确?


3
“使用typedef不会有不便之处”?不清楚你确切的问题是什么。此外,请注意,除了少数例外情况,C代码也是有效的C++代码(虽然在C++中并不一定是最好的选择),所以你的C代码片段应该可以编译并正常工作。 - einpoklum
3
typedef float real; 不要这样写。代码是关于沟通的,而你在这里没有很好地进行沟通。所有的C和C++程序员都知道float是什么,但是他们不知道你所说的real确切含义。当然,他们可以查阅资料,但你让说明意图变得更加困难了。这个typedef并不是抽象,只是一种语法糖。 - StoryTeller - Unslander Monica
1
在 C 语言中,你需要使用 typedef 来避免每次都写 struct RECID。而在 C++ 中,你可以自动使用不带 structRECID - πάντα ῥεῖ
1
如果你想在C++中使用C语言编写的内容,那么请查看extern C {}的概念。如果你想编写一个C到C++的包装器,那么请与Bjarne Stroustrup分享你们的经验。他曾经成功地做过类似的事情,但是这需要很多工作,许多人都注意到了这一点。 - Yunnosch
2
此外,typedef float real;float real; 是两个不同的东西。 - CompuChip
显示剩余6条评论
3个回答

10

这一行:

typedef float real;

实际上只是一个 typedef,它将 real 定义为类型 float 的别名。因此,如果你写

float real;

在C和C++中,这并不相同。它只是一个声明变量real的语句,并指定了其类型为float


structenum会更加复杂一些,因为它们有所谓的标签来区分它们:

struct foo
{
    int x;
};

这里:foo是结构体的标记。在C++中,只需编写标记即可引用结构体(只要标记名不歧义),而C需要您始终包含struct关键字:

struct foo a; // legal in both C and C++
foo b;        // legal only in C++

当然,您也可以使用 typedef 创建别名类型,以上面的示例为例:

typedef struct foo foo;

现在,第二个声明也是有效的C代码,因为foo是一个类型名称。

同样的规则也适用于enum

请注意,C++不会自动typedef一个structenum。它只允许使用标记名称单独引用这些类型。因此,额外的typedef在C++中是完全有效的。

因此,如果您的代码应该同时与C和C++一起工作(这通常只适用于头文件),只需像这样声明您的struct

typedef struct foo foo;
struct foo
{
    // members
};

或者压缩为单个声明:

typedef struct foo
{
    // members
} foo;

请提供完整的需要翻译的内容,以便我能够更好地进行翻译。
struct foo
{
    int x;
};

typedef struct foo *foo;

(旁注:对指针进行typedef是一种不好的习惯,这里只是为了简单演示)

这段代码是有效的C代码,但不是有效的C++代码。原因是C++要求typedef与结构体或枚举类型具有相同的名称,以引用完全相同的结构体或枚举类型。在C中,没有这样的要求。


谢谢您的解释,但是我仍然有一些关于RECID情况的问题。如果我理解您的意思正确,在第二个typedef示例中,我也可以像在C++中一样保留它吗? - N.M.G.
@Nusha_Gadim,你展示的RECID的最终示例是错误的,它尝试向同一结构体添加两个结构标记(_hf_record_identificationRECID),这是不可能的(两种语言都是如此)。只需将其保留为第一个版本即可...结构体的typedef不必使用与结构体标记相同的名称,因此第一个代码在两种语言中仍然有效。 - user2371524

1
这种方法已经非常过时了。为了编写与C++兼容的C代码,您应该使用两种语言的本机bool类型(在1999年引入了C语言),而不是一些20世纪90年代的宏。 #include <stdbool.h> 然后使用 booltruefalse
即使不需要C ++兼容性,在C中使用自己制作的自定义bool类型也总是不好的实践。

7
这应该是一条评论,因为它并没有真正回答问题。尽管如此,给出了非常好的建议。 - cmaster - reinstate monica
@cmaster 这个问题是“我的问题是,为什么在C++中使用typedef不方便?”答案是,在任何一种语言中都不应该使用typedef来定义布尔类型。 - Lundin
7
不是的,问题要宽泛得多。请注意 OP 给出 structenumfloat 的例子。bool 只是一个旁支。 - cmaster - reinstate monica
@polkovnikov.ph 它确实试图回答这个问题。如果没有回答到,那么可能是因为问题不清楚,我误解了它。在这种情况下,应该关闭这个问题。 - Lundin
@polkovnikov.ph 我非常清楚。作为审阅者,您的任务是确定答案是否试图回答问题。删除投票是针对那些没有试图回答问题的答案,而不是仅仅质量较差的答案。 - Lundin

0

重新创建C接口,仅通过将typedef enum {} X替换为enum X {}等方式并不会有太多(更确切地说是没有)用处,因为C代码也可以很好地被C++接受 - 除非您面临任何那些与C++不兼容的C特性(例如在头文件中使用的VLA内联函数)。否则,您只是复制代码,这将导致可维护性问题而没有任何进一步的利润。

当然,C++包装器可能是有用的,但您需要为现有的C接口创建类似于C++的接口,引入面向对象和可能的多态性,如下所示:

// FILE wrapper in C++:
class File
{
    FILE* handle;
public:
    int read();
    int write();
    // or whatever you consider appropriate
};

// sockets:
class Socket
{
public:
    // some appropriate common interface
};
class SocketTCP : public Socket
{
    // appropriate specialization...
};
class SocketUDP : public Socket
{
    // appropriate specialization...
};

很可能,您可以用这样的类替换C结构体,这些类将包装C类型,然后枚举类型,但是,除非您希望它们具有不同的作用域(例如将其中一些嵌套在类或命名空间中),否则您可以将它们保持原样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接