C++在全局命名空间中找不到非标准C函数

6
我们有一个相当大的C ++项目,我现在正在将其移植到VS2010并更新其中几个库。到目前为止,除了我收到一些(对我来说)相当奇怪的错误消息之外,一切都构建得非常好。这些错误似乎是因为许多(更正: 非标准的)C函数和符号未定义:
error C2039: 'strdup' : is not a member of '`global namespace''    ...\ACE_wrappers\ace\OS_NS_string.inl    222
...
error C2065: 'O_WRONLY' : undeclared identifier                    ...\ACE_wrappers\ace\OS_NS_unistd.inl    1057
...

这对我以下的功能和符号产生影响:
strdup      getcwd      O_WRONLY
putenv      swab        O_TRUNC
access      unlink      S_IFDIR
chdir       mkdir       S_IFREG
rmdir       tempnam     O_RDONLY
isascii

在我尝试的ACE包含文件中,有一个与strdup相关的部分,如下所示:

ACE_INLINE char *
ACE_OS::strdup (const char *s)
{
#  if (defined (ACE_LACKS_STRDUP) && !defined(ACE_STRDUP_EQUIVALENT)) \
  || defined (ACE_HAS_STRDUP_EMULATION)
  return ACE_OS::strdup_emulation (s);
#  elif defined (ACE_STRDUP_EQUIVALENT)
  return ACE_STRDUP_EQUIVALENT (s);
#  elif defined (ACE_HAS_NONCONST_STRDUP)
  return ::strdup (const_cast<char *> (s));
#else
  return ::strdup (s);
#  endif /* (ACE_LACKS_STRDUP && !ACE_STRDUP_EQUIVALENT) || ... */
}

以上和以下有许多类似的部分,涵盖了其他功能,所有这些部分都可以编译通过。

在我的情况下,采用的是最后一种方式,即return ::strdup (s);。如果我在::strdup上按F12,VS会将我带到C标准库中string.h的声明处。

如果我删除命名空间限定符,它就能构建,尽管IntelliSense告诉我它现在是一个递归调用,所以它可能行不通。如果我将命名空间更改为std::,就会得到大约270个更多的错误,这次来自于几个其他项目。如果我将函数更改为::_strdup,它就能构建。将string.h作为第一件事包含进来并没有改变什么。

(Nota bene:“它能构建”指的是“这个特定的编译器错误在那个位置消失了,但显然还留下了关于其他函数的错误。”)

我有点茫然。我注意到许多较大的库要么构建自己的抽象库,要么提供默认情况下不存在的东西,这是ACE和ImageMagick已经冲突的一个点(都在typedef中使用ssize_t,但定义不兼容)。由于我们引入了相当多的库(我现在也没有确切的概述),这可能是另一个冲突,由错误的包含顺序和类似的问题引起。这也可以从ACE的相同包含在同一解决方案中的其他项目中工作良好的事实所暗示。

有人有什么想法至少可以在这里寻找吗?带有/showIncludes的构建日志只有24k行,因此我并没有看到很多模式,除了string.h在有问题的ACE头文件之前被包含进来。

而且我不想修改库源代码,因为如果我们更新到新版本,它只会再咬我们一口。


在C++中,官方的头文件名称是<cstring>,而非<string.h> - ipc
2
你可以使用其中任何一个,它们的区别在于函数是否出现在全局命名空间中,只有 可能 出现在 std 中,或者它们是否出现在 std 中,只有 可能 出现在全局命名空间中。不过这并没有什么区别。至少我是这样理解的。 - Joey
1
你尝试过仅对代码进行预处理并验证结果输出中的函数是否在全局命名空间中吗?(如果<string.h>意外地被包含在namespace <blah> {中会怎样?) - Mark B
从谷歌搜索来看,ACE在VS上得到了支持。也许你的解决方案缺少一些定义?你能否从原始来源下载VS解决方案文件? - Robᵩ
Mark B:非常感谢;虽然预处理输出结果和/showIncludes的构建输出结果差不多难以阅读,但这确实让我找对了方向。 - Joey
显示剩余2条评论
3个回答

4
“许多标准C函数和符号未定义”。 strdup不是标准的C函数。它在POSIX中定义,但不在C或C++中定义。引用MSDN: “这些POSIX函数从Visual C++ 2005开始被弃用。使用ISO C++兼容的_strdup、_wcsdup、_mbsdup代替。” 在我看来,您列出的所有符号都不是标准的C函数。

好的,从技术上讲,你是正确的,并指出了问题的部分根本原因,但这并没有在解决问题方面提供任何帮助。 - Joey
我以前从未见过“ISO C++兼容”这个短语被用来表示“由微软编造”的意思。 - Mike Seymour
1
@Mike Seymour 这意味着因为它们在全局命名空间中并且以“_”开头,编译器允许使用这些名称。 - Mark B

1
通过 Mark B 的评论,促使我查看了 12 MiB 的预处理器输出,最终解决了问题。在 string.h 中,定义 strdup 的代码片段如下:
#if     !__STDC__

...

_Check_return_ _CRT_NONSTDC_DEPRECATE(_strdup) _CRTIMP char * __cdecl strdup(_In_opt_z_ const char * _Src);

恰好这个单一项目定义了__STDC__符号,导致许多非标准C但仍在C标准库中的函数(感谢Robφ挑剔但未解决问题)完全消失。

我知道它们已被弃用,我收到了很多警告来告诉我这一点。但正如所指出的,我不会维护特定于项目的补丁以使用我们使用的第三方库,只是为了如果我们更新它们,再次体验同样的乐趣。


0
如果我理解正确的话,strdup等函数名现在已经被弃用了(我认为不符合POSIX标准)。你应该使用下划线版本。
当我遇到这种情况时,我进行了全局搜索和替换,因为这似乎是一个明智的做法,并且可以保持源代码的良好状态以供将来使用(VS 2012已经发布了! :))。

除了不是我在使用它们而是另一个库之外。 - Joey

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