首页 > 编程知识 正文

c++11条件变量,c14怎么吹气

时间:2023-05-05 18:04:15 阅读:135639 作者:3193

这里有一个小的测试APP演示。 正在使用的isnan。

#包含

#包含

int main () )

{

double d=NAN;

STD:3360coutIsnan(d ) '

';

返回0;

}

按照三个不同的标准构建和执行:

$ g -std=c 98 main.cpp;/a.out

1

$ g -std=c 11 main.cpp;/a.out

1

$ g -std=c 14 main.cpp;/a.out

1

这里使用isnan和std:isnan进行测试。

#包含

#包含

#包含

int main () )

{

double d=NAN;

STD : cout STD :3360 isnan (d ) '

';

STD:3360coutIsnan(d ) '

';

返回0;

}

构建并运行:

C 98可以工作

$ g -std=c 98 main.cpp;/a.out

1

1

没有找到C 11和C 14,isnan。

$ g -std=c 11 main.cpp

main.CPP : in function‘int main ()’:

main.CPP :103360253360 error :‘isnan’wasnotdeclaredinthisscope

STD:3360coutIsnan(d ) '

';

^

main.CPP :103360253360 note :子身份验证:

infileincludedfrommain.CPP :336003360033600336003360

/usr/include/c/5/cmath :641336053360 note :‘STD 3360: isnan’

isnan(_TP__x ) ) ) ) ) ) ) ) isnan(_TP__x ) ) ) ) ) ) ) ) isnan ) ) ) ) ) ) )。

^

$ g -std=c 14 main.cpp

main.CPP : in function‘int main ()’:

main.CPP :103360253360 error :‘isnan’wasnotdeclaredinthisscope

STD:3360coutIsnan(d ) '

';

^

main.CPP :103360253360 note :子身份验证:

infileincludedfrommain.CPP :336003360033600336003360

/usr/include/c/5/cmath :641336053360 note :‘STD 3360: isnan’

isnan(_TP__x ) ) ) ) ) ) ) ) isnan(_TP__x ) ) ) ) ) ) ) ) isnan ) ) ) ) ) ) )。

^

请注意,包含的顺序并不重要。 如果我包含在之前或之后,结果是一样的。

问题

为什么isnan消失了?

虽然不需要更改回旧代码并使用新标准进行编译,但是有解决这个问题的方法吗?

Clang是使用libc还是使用与gcc相同的libstdc?

@ildjarn ldd表明它是相同的(/usr/lib/x86 _ 64-Linux-GNU/libstdc.so.6 )。 我编辑了这个问题,删除了clang部分。

奇怪的问题.如果交换了包含cmath和math.h的字符串怎么办? 关于我,我会避免使用cmath这样的c *标题

@AntonMalyshev你问的包含顺序是? 这没什么区别。

编译器的版本是什么? 我不能用col再现g和clang。

@AntonMalyshev不可避免地使用c *标头-这是旧代码,必须作为使用更新标准构建的更大代码库的一部分来构建

@NathanOliver我在使用g 5.4.0。 glibc版本是2.23

哼哼。 显然,coliru使用的是ubuntueglibc 2.15-0 Ubuntu 10.13 (ldd ) 2.15

@NathanOliver注意到你的评论,尝试了Wandbox。 虽然没有gcc-5.4.0,但确实有5.3.0和6.1.0。 我也复印不了……非常奇怪!

请勿同时使用cmath和math.h .

可能是图书馆的错误。 gcc.godbolt.org位于4.9.2至5。

3之间失败但在6.1上工作

@Ven,我不是。有问题的代码使用math.h。但是,我假设其他一些包含的内容包括最终包含cmath的内容,因此两者都在范围内。因此编译失败,因此我编写这个小应用程序来诊断正在发生的事情

@NathanOliver非常有趣! gcc.godbolt.org无法编译5.3,而wandbox适用于5.3。

非常离奇。看看这种不一致的原因是多么有趣。对不起,我只能混淆问题:)

@NathanOliver不,谢谢你帮忙确认我不是疯了!我会看看bugzilla,看看能不能找到任何东西

@NathanOliver我在Centos gcc-4.9.1和gcc-5.2.1上运行它,它适用于两者。在Ubuntu gcc-4.9.3上运行它,但gcc-5.4.0没有。鉴于godbolt对某些人失败了,但是wandbox没有...好吧,我不知道该怎么想?!

@SteveLorimer如果你在几天内没有找到任何东西给我一个ping,我会给你一个赏金。我真的很想知道发生了什么。

简要总结相关要点,主要来自Jonathan Wakely的优秀博客文章:

glibc <2.23的math.h声明过时的X / Open int isnan(double);与C99 / C ++ 11版本(bool isnan(double);)不兼容。

glibc 2.23的math.h通过不在C ++ 11或更高版本中声明isnan函数来解决这个问题。

所有这些仍然定义了一个isnan宏。 #include根据C ++标准的要求核对该宏。

GCC 6的libstdc ++提供了自己的特殊math.h头,它在全局命名空间中声明了一个bool isnan(double);(除非libc math.h声明了过时的签名),并且还按照标准的要求来核对宏。

在GCC 6之前,#include只包含libc中的标题,因此宏不会被破坏。

#include总是核心宏。

净结果,在C ++ 11模式下:

glibc <  2.23, GCC <  6: uses the macro; uses obsolete signature

glibc >= 2.23, GCC <  6: uses the macro; results in error

glibc <  2.23, GCC >= 6: and use obsolete signature

glibc >= 2.23, GCC >= 6: and use standard signature

@NathanOliver你看到了这个答案吗?

谢谢 - 非常翔实!

@SteveLorimer我现在有。 谢谢T.C. 另一个很好的答案。

如果从GCC查看,它有:

. . .

#include

. . .

#undef isnan

这就是订单无关紧要的原因 - 无论何时#include,都是自动包含的,其内容是(部分)核心的。

由于#ifndef _MATH_H,尝试再次包含它将无效。

现在,标准对这种行为有什么看法?

[depr.c.headers]:

... every C header, each

of which has a name of the form name.h, behaves as if each name placed

in the standard library namespace by the corresponding cname header is

placed within the global namespace scope. It is unspecified whether

these names are first declared or defined within namespace scope

([basic.scope.namespace]) of the namespace std and are then injected

into the global namespace scope by explicit using-declarations

([namespace.udecl]).

[ Example: The header assuredly provides its declarations

and definitions within the namespace std. It may also provide these

names within the global namespace. The header assuredly

provides the same declarations and definitions within the global

namespace, much as in the C Standard. It may also provide these names

within the namespace std. — end example ]

所以在全局命名空间中不提供isnan是可以的。

但是当它们都被包含在一个编译单元中时,它应该是一个灰色区域,尽管可以说上面的语句暗示两个版本必须互操作,在这种情况下它将是GCC / libstdc ++(某些版本)中的错误。

math.h中的许多函数实际上都是宏。由于这不是惯用的c ++,标头cmath包含以下代码:

...

#undef isinf

#undef isnan

#undef isnormal

...

然后将所有那些未定义的宏实现为namespace std中的函数。对于gcc 6.1.1,这至少是正确的。这就是你的编译器找不到isnan的原因。

我可以在godbolt上编译gcc-6.1上的std::isnan和isnan

如果它与undef有问题,那么包含的顺序就很重要,但这并不重要

@AntonMalyshev:为什么订单很重要? cmath几乎总是包含math.h,它将有一个标题保护 - 它将始终包含一次,并且只包含一次。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。