C ++“size_t”不需要“cstddef”头?

时间:2018-01-12 21:50:27

标签: c++

我正在学习使用C ++ Primer一书的C ++,它说“size_t”在“cstddef”标题中定义,但是在本练习中:

#include <iostream>

using namespace std;

int main()
{
    int ar[10];

    for (size_t x = 0; x < 10; ++x)
        ar[x] = x;

    for (auto a : ar)
        cout << ar[a] << " ";

    cout << endl;

    return 0;
}

没有包含标题,Visual Studio 2017(和c ++ shell)编译程序时没有错误。

5 个答案:

答案 0 :(得分:4)

size_t实际上是一个灰色区域。 std::size_t是[{1}}的结果类型,但sizeof是一个内置运算符,您可以在没有任何sizeof的情况下使用它。考虑这个完整的小程序:

#include

最重要的是,Visual C ++在这里总是表现得有些奇怪。即使在最新版本的编译器中使用// no includes, no using namespace std int main() { auto x = sizeof(int); // x is std::size_t } 之类的设置,它仍然允许以下非法代码:

/permissive- /std:c++latest

事实上,它甚至会允许这个

// no includes, no using namespace std

int main()
{
    size_t i  = 0;
}

然而,其他人所说的间接包含标题是正确的。确切地说,C ++标准在§20.5.5.2中描述了以下关于标准库头的内容:

  

C ++标头可能包含其他C ++标头。

这意味着Visual C ++无论如何都会在您的情况下正常运行。一旦你加入// no includes, no using namespace std int main() { int ar[10]; for (size_t x = 0; x < 10; ++x) ar[x] = x; for (auto a : ar) ; return 0; } ,实现就可以间接地包含six standard C++ headers that define std::size_t中的一个,而你的<iostream>(这是邪恶的)会完成其余的工作。

C ++标准甚至保证了一些这样的间接包含,但这不是其中之一,因此为了使您的代码与其他编译器兼容,强烈建议您包含using namespace std;或其中一个保证<cstddef>的其他人。

答案 1 :(得分:2)

允许标准标头包含其他标准标头。由于不同实现中的标头具有不同的依赖关系,因此您仍应尝试明确包含所需的所有内容。例如,您的程序可能不会构建在Linux的libstdc ++或macOS的libc ++上。

答案 2 :(得分:2)

标准标题通常会包含其他标准标题,因此在许多情况下,您可能会因为不包含正确的标题而离开。

问题是标题之间的这种关系不在标准中,例如取决于实施。如果您没有包含必需的标头,那么您的代码可能在一个编译器上运行,但在另一个编译器上可能会失败。

通常,如果你知道标题X中定义的东西在其定义中使用了类型T,你可能会假设类型T在包含X之后可用。例如<vector>使用std::size_t作为{{{1}的一部分1}}定义,因此它通常包含std::vector

有时可以使用前向声明来避免包含其他标准标头。但这只适用于类和结构,而不是typedef。

某些实现(例如GNU Libc)更严格,并尽量避免在内部包含标准头。其他人,如MSVC,则不那么严格。与GNU Libc一起使用的代码通常适用于MSVC。

很难验证您的代码是否包含您需要的所有内容。有些工具可以帮助您找到遗漏的内容,但使用多个编译器构建代码通常是找到这些问题的最佳方式。

答案 3 :(得分:2)

首先,std::size_t在多个标准标题中定义:<cstddef><cstdio><cstdlib><cstring><ctime><cwchar>

如果没有#include其中一个,则不需要编译代码。

实际上,标准库的许多实现都有各种标准头#include,在这种情况下你的代码将被编译。这是非常常见的,但不能保证,至少有一个标头定义std::size_t(甚至它们的C标头等价物,如<stddef.h>)将被C ++标准库中的其他标头包含。< / p>

更具体地说,标准库工作的很多部分都使用动态内存分配(标准容器,流缓冲区等)。一个明显但不是必需的实现选择是他们使用size_t来表示大小。例如,std::vector之类的标准容器具有关联的size_type,而std::vector<any_type>::size_type可以且通常等同于std::size_t

<iostream>(以及自动#include s的标题)不需要包含定义std::size_t的标题,但是 - 同样 - 标准中没有任何内容不允许它。

最后,它归结为您对可携带性的谨慎态度。如果<iostream>使用您的特定编译器引入std::size_t的定义,那么您的代码将被编译。有可能(虽然在实践中不太可能,但并非不可能),未来的编译器版本将更新标准头以更改它。如果您打算将代码移植到另一个实现(编译器和标准库),则更有可能需要修改代码。

实际上,明确#include <cstddef>或任何其他定义std::size_t的标头都没有任何危害。这样,使用std::size_t的代码将进行编译,无论其他标准标头在实现之间如何变化。

答案 4 :(得分:1)

不,std::size_t可能在多个标题中定义:

Defined in header <cstddef>
Defined in header <cstdio>
Defined in header <cstdlib>
Defined in header <cstring>
Defined in header <ctime>
Defined in header <cwchar>

另请注意,<iostream>本身包含其他标题。