返回空字符串文字 VS。返回 nullptr - 它们是否相同?

Returning an empty string literal VS. returning a nullptr - Are they the same?

我最近在我开发的应用程序的 public SDK 中发现了以下功能:

virtual char* ExtentName() {return "";}

当我使用带有 /permissive- 标志的 Visual Studio 编译应用程序时,上面的函数导致以下编译错误:

error C2440: 'return': cannot convert from 'const char [1]' to 'char *'
note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)

我真的很惊讶这段代码在任何情况下都能编译,因为它将字符串文字(在本例中为空终止符)转换为 char*。这怎么可能?

此外,我想在不导致 SDK 中断的情况下解决此问题。这是我认为最好的解决方案:

virtual char* ExtentName() {return nullptr;}

上面的更改不会破坏 ABI,但我担心它会破坏我们用户的代码,尽管我不确定如何破坏。有这种可能吗?感谢您提供任何信息!

自 C++11 以来,禁止在没有 const 限定的情况下将字符串文字隐式转换为 char*

MSVC 无论如何都允许它向后兼容,因为早期版本的 C++ 允许它。 /permissive- 标志使其行为符合标准。

第一个函数 return 不是一个空指针值,它 return 是一个指向字符串文字的有效指针,它将是一个长度为 char 的数组 1 仅包含空终止符。因此这两个功能完全不相等。

第二个函数 return 是一个空指针值,与第一个函数的 return 值相比,可以例如不能间接通过。

从技术上讲,您可以通过显式 const_cast:

来保留函数签名
virtual char* ExtentName() { return const_cast<char*>(""); }

它本身具有明确定义的行为,但是任何尝试写入从该函数 returned 的指针指向的数组都将导致未定义的行为,而编译器不会发出警告。

因此不应该这样做。但是,如果您已经针对以前的 C++ 标准或许可编译器编译了原始函数,那么该函数已经做到了这一点,并且不会引入任何 new UB 风险。通过 returned 指针写入在原始代码中也将是 UB 而没有警告。

正确的做法是使 return 值 const char*,因为显然不允许用户修改此函数指向的值 return。可能从一开始就没有这样做是个错误。

不,它们根本不一样。目前,函数 return 是指向 c 字符串的有效指针,大概在所有情况下都是如此。如果您将其更改为 sometimes return a nullptr,任何依赖有效性而不检查中断的代码。

理想情况下,您会 return 一个 std::string,但这需要使用该函数更改代码。

将函数更改为return一个const char*。这将清楚地表明此 c 字符串是 const。这只有 "breaks" 代码错误地假定它不是 const,但这是一件好事,因为 c 字符串 const.

如果无法更改 ABI,请保持原样。