为什么C++中的多定义错误不是由const int声明引起的

Why multiple definition error in C++ not caused by const int declaration?

本文关键字:const int 声明 C++ 定义 错误 为什么      更新时间:2023-10-16

我有一个头文件foo.h:

#ifndef __FOO_H__
#define __FOO_H__
const char* USB_MANAGER_DBUS_SERVICE =  "com.USBService";
#define  USB_MANAGER_DBUS_OBJ_PATH  "/com/USB/MgrObject"
const int  DBUS_CONNECTION_MAX_RETRY_TIME  = 5;
#endif

以及许多包含foo.h的cpp文件。

foo.c bar.c

将它们编译在一起时,会出现"多重定义错误"。

Linking CXX shared library:
foo.cpp.o:(.data.rel.local+0x0): multiple definition of `USB_MANAGER_DBUS_SERVICE'
bar.cpp.o:(.data.rel.local+0x0): first defined here

所以我有两个问题:

  1. 为什么#define不会导致链接错误
  2. 为什么const int不会导致链接错误

USB_MANAGER_DBUS_OBJ_PATH#define在各个编译单元中是常量,它是一个文本替换。

TU中DBUS_CONNECTION_MAX_RETRY_TIME常量的const int也是如此。const使变量只读,本质上是而不是将其声明为可修改的左值,它有一个隐含的内部链接,来自这些帖子。

const char* USB_MANAGER_DBUS_SERVICE =  "com.USBService";

为什么USB_MANAGER_DBUS_SERVICE会导致链接器错误

它不是const,因为在指针中不是一个常数值,只有被指向的内容

const char* const USB_MANAGER_DBUS_SERVICE =  "com.USBService";
//          ^^^^^ added const

将是const

Define不会导致链接错误,因为预处理器只是将字符串文本粘贴到代码的不同部分,而不是引用某个对象文件中定义的某个对象。

const int不会导致链接错误,因为const意味着内部链接,所以最终每个编译单元都有一个常量。

您可以通过在头文件中定义extern const char* USB_MANAGER_DBUS_SERVICE;并在某个源文件中定义const char* USB_MANAGER_DBUS_SERVICE = "..."来修复重新定义错误。

"#define"d令牌已经由预处理器处理,甚至在编译器开始运行之前。

在C++中,"const int"值是在编译时计算的,即"const int"等效于类型安全定义(因此应该优先于#define)。

编译器实际为链接器创建的唯一符号是"USB_MANAGER_DBUS_SERVICE",因为只有指针指向的目标是"const",而不是指针本身。

问题出在这里。通过使用#ifndefFOO_H包装器,可以避免在.c或.cpp文件中多次包含FOO.H,但当链接器将所有不同的对象文件链接在一起时,会有多个定义。补救措施是你在foo.h:中使用如下方法

#ifndef __FOO_H__
#define __FOO_H__
extern const char* USB_MANAGER_DBUS_SERVICE;
#define  USB_MANAGER_DBUS_OBJ_PATH  "/com/USB/MgrObject"
extern const int  DBUS_CONNECTION_MAX_RETRY_TIME;
#endif

并且,仅在一个.c或.cpp文件(即一个源文件)中,使用以下内容:const char*USB_MANAGER_DBUS_SERVICE="com.USBService";const int DBUS_CONNECTION_MAX_RETRY_TIME=5;

这将解决链接器抱怨的多重定义问题。

const char* USB_MANAGER_DBUS_SERVICE =  "com.USBService";

该指针指向的字符串是const,但指针不是const,因此它是一个多重定义。将其更改为

const char USB_MANAGER_DBUS_SERVICE[] = "com.USBService";

const int没有链接错误,因为它是一个实常量,而不是const修饰符。因此,它被认为是应用程序的static数据。

顺便说一句,如果你为指针输入另一个常量

const char* const USB_MANAGER_DBUS_SERVICE = "com.USBService";

现在这个指针也是一个适当的常数,但我不确定它是否有效。您可以将它声明为extern,然后在一个编译单元中定义它,但最简单的是我向您展示的第一个语法。