为啥 VS 不为逻辑运算符定义替代标记?

Posted

技术标签:

【中文标题】为啥 VS 不为逻辑运算符定义替代标记?【英文标题】:Why does VS not define the alternative tokens for logical operators?为什么 VS 不为逻辑运算符定义替代标记? 【发布时间】:2014-06-25 16:33:46 【问题描述】:

替代标记是 valid c++ keywords,但在 Visual Studio 2013 中会发出编译错误(未声明的标识符):

int main(int argc, const char* argv[])

    int k(1), l(2);
    if (k and l) cout << "both non zero\n";

    return 0;

and or not 已经存在很长时间了,是否有理由不实施它们

【问题讨论】:

错误信息是什么究竟 我想知道为什么会这样。这不可能是实现的复杂性,如果他们害怕破坏旧代码,同样应该适用于 gcc 等。一个简单的 grep/replace 就可以解决他们的任何代码库冲突,那么是否有更深层次的原因,是幕后有争议还是只是一个没人关心的功能? @NikosAthanasiou 一个简单的 grep/replace 可能会搞砸很多 cmets。 GCC 通常比 MSVC 在以符合标准的名义破坏旧代码方面更多更随意。 【参考方案1】:

您询问原因。这是一个可能的原因,不一定是对 Visual C++ 团队影响最大的原因:

    这些是 C 中的有效标识符。 长期以来,Microsoft 的建议是对 C 和 C++ 代码都使用 C++ 模式,而不是维护现代 C 编译器。 使用这些作为标识符的有效 C 代码如果被编译为关键字,将会无缘无故地中断。 尝试编写可移植 C++ 的人大多使用 /permissive-/Za 以获得最大的一致性,这将导致这些被视为关键字。 通过包含头文件将它们视为/Ze 中的关键字的解决方法既简单又可移植。 (G++ 的解决方法-fno-operator-names 也不错,但是将选项放在源代码中而不是构建系统中会更好一些。)

【讨论】:

能否修改/Za 部分,好吗?显然它有很多错误,微软不鼓励使用它(当然,grrr 不在文档中)。见reddit.com/r/cpp/comments/76pmky/til_c_has_and_or_and_not/… 另外请注意,/Za 会导致 MSVC 中出现错误,当包含windows.h 时会触发编译器错误。我在查看此帖子后遇到此问题,因此对此进行了报告:github.com/SasLuca/MSVCBug/blob/master/README.md 如果您遇到/Za 的问题,请改用/permissive-【参考方案2】:

VS 不合格。这是旧闻。

要使用替代标记,请包含 &lt;ciso646&gt; 标头。根据标准,包含此标头应该在 C++ 中无效。但是,您在 VS 中确实需要它。因此,只要有可能使用 VS 进行编译,始终包含它是安全的。

【讨论】:

正如已经指出的,这种“不符合”仅特定于默认编译设置。大多数(如果不是全部)编译器在默认模式下不符合标准。指定 /Za 选项会从 VS 编译器中删除这种不符合项。 gcc 与 C++11 或更高版本没有 -pthreads 选项是另一个很好的例子。【参考方案3】:

形式上,这些关键字 被编译器实现并在本质上得到支持,而不包括任何头文件。但是,为此,您必须在 C++ 编译器的“更标准”模式下编译源代码,这意味着使用 /Za 选项。

根据意图,/Za 选项应该“禁用编译器扩展”。当然,不支持兼容编译器中应该存在的东西不能正式限定为“编译器扩展”。然而,这正是目前的情况。

【讨论】:

不回答“为什么?”的问题 @Ben Voigt:嗯,它认为“为什么”部分来自“为什么不实施?”。这样的问题是基于一个不正确的前提,因为它们实际上已经实现了。 “扩展”是让程序员将这些名称作为标识符。 @Ben Voigt:是的,但是“扩展”的正式定义明确表示不允许扩展破坏任何合规代码。换句话说,真正的扩展允许“定义标准未定义的内容”,但不允许“取消定义(或重新定义)标准已经定义的内容”。形式上,允许扩展extend可编译代码的域,但不允许收缩它。 遗憾的是,这对我来说实际上不是一个选项,因为它会导致标准标题中出现很多错误,例如winnt.h(12723): error C2467: illegal declaration of anonymous 'struct'【参考方案4】:

现代 Visual Studio(或者更确切地说,MSVC)确实支持替代令牌;但是,它只在standards conformance mode 中这样做。这种模式有很多好处,所以应该一直使用它。

要启用它,请将/permissive- 传递给编译器。


以下答案已过时。现在支持,见上文!

以前,Microsoft’s position was1 那个

#include&lt;iso646.h&gt;(或ciso646)是我们支持这些关键字的方式

因为“没有人”(在我之前,2007 年)曾经要求过这个。

1 链接目前已失效;留在这里存档。

【讨论】:

【参考方案5】:

(当代更新)

我做了一个小测试:一个新的“Windows 桌面应用程序”项目。 IDE (Visual Studio 2017 15.7.5) 默认设置以下 C++ 语言一致性设置:/permissive- /Zc:wchar_t /Zc:forScope /Zc:inline。此外,我将 C++ 语言标准 设置为 ISO C++ /最新草案(目前最高为 C++ 17).此外,我在 main() 中添加了以下 2 行:

bool a, b, c;

a = b and c;

它成功地编译了逻辑运算符的文本形式。但是当我将 IDE Conformance mode 更改为 No (=> without /permissive -) 并重新编译,编译器标记:“error C2065: 'and': undeclared identifier”。

默认情况下,/permissive- 编译器选项设置在由 Visual Studio 2017 版本 15.5(2017 年 12 月)及更高版本创建的新项目中。在早期版本中默认未设置。因此,如果有人在 15.5 版本之前创建了一个项目,并且在将 IDE 更新到最新版本时,仍然需要在项目中手动设置此编译器选项。

/Ze 编译器选项(默认启用)启用 Microsoft 扩展。 /Ze 选项已被弃用,因为它的行为默认为开启。 MSDN 建议使用 /Zc(一致性)编译器选项来控制特定的语言扩展功能。

【讨论】:

以上是关于为啥 VS 不为逻辑运算符定义替代标记?的主要内容,如果未能解决你的问题,请参考以下文章

为啥按位运算符不如逻辑“和\或”运算符聪明

反应渲染逻辑 && vs 三元运算符

当按位运算符做同样的事情时,为啥要使用逻辑运算符?

为啥 JavaScript 中的逻辑运算符是左关联的?

为啥 ~= 在 C++ 中缺少唯一的非逻辑赋值运算符? [关闭]

tcl 关系和逻辑运算符总结