我目前正在阅读Lahoie,Lippman和Moo的第五版C ++ Primer,并且一直在努力解决一些问题。
首先,我只想确认,在使用任何cctype
函数时,我必须确保包含标题,对吧?因为,最初,我忘了包含它,但它仍然运行。这让我很困惑。
另外,我正在浏览一个不同的问题(我会去)并发现另一个问题哈哈!使用cctype
中的任何内容时,我是否应该将其写为std::/write using std::
,例如如果我使用tolower
在每个实例上写std::tolower
/为它写一个using语句。这是有道理的,因为它确实说它们是“在std
命名空间中定义的”但我没有意识到并且一直在编写它而没有出现问题。我猜size_t
类似,对吧?
说到size_t
,我有一个问题。这是我的代码:
// Exercise Section 3.5.2., Exercise 3.30
#include <iostream>
#include <cstddef>
using std::cout; using std::endl;
int main()
{
constexpr size_t num_size = 10;
int num[num_size] = {};
for (size_t n = 0; n < num_size; ++n) {
num[n] = n;
cout << num[n] << endl;
}
return 0;
}
因此,代码应该定义一个10 int
s的数组,并为每个元素赋予与其在数组中的位置相同的值。
它运行正常,但我在num[n]=n
部分收到错误。它说Implicit conversion loses integer precision: size_t (aka 'unsigned long') to int
。
我理解这意味着什么,但我的问题是本书说“当我们使用变量来下标数组时,我们通常应该定义该变量以键入size_t
”。我做了这个,它给出了这个错误。它确实运行良好,但似乎可能会导致错误。
P.S。在此代码中,就像我上面提到的那样,我应该using std::size_t
吗?
答案 0 :(得分:4)
我必须包含标题,即使它没有吗?
是的,您必须始终包含至少一个标题,提供您需要的每个定义/声明,除非确保原型/类型定义,并将其直接放入源代码中。
某些标准标题可能包含其他标准标题,这可能会让您在某些时候变得松懈,但是在升级/移植到其他实现的那一天,您将会对它进行谴责。
我读了所有的声明和定义是“在std命名空间中定义的”,但我没有意识到并且一直在编写它并且没有出现问题。而我猜测size_t类似,对吧?
是的,它是一样的。由于兼容性,包含在C / Unicode中的<c...>
标头也可以在全局名称空间中提供它们的符号。
17.6.1.2标题
[headers]
1 C ++标准库的每个元素都在header.175中声明或定义(视情况而定) 2 C ++标准库提供了55个C ++库头,如表14所示 3 C标准库的设施在26个附加标题中提供,如表15所示 4除第18条至第30条和附件D中所述外,每个标题cname的内容应与C标准库(1.2)或C Unicode TR中指定的相应标题name.h的内容相同,如适当的,好像通过包含。但是,在C ++标准库中,声明(除了在C中定义为宏的名称除外)都在命名空间std的命名空间范围(3.3.6)内。 未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明(7.3.3)注入命名空间std。
5在C语言库中定义为宏的名称应在C ++标准库中定义为宏,即使C授予实现许可证作为函数。 [注意:在C中定义为宏的名称包括以下内容:assert,offsetof,setjmp,va_arg,va_end和va_start。 - 注意事项]
6在C中定义为函数的名称应定义为C ++标准库中的函数.176
7作为C ++中关键字或运算符的标识符不应在C ++标准库头中定义为宏.177 8 D.5,C标准库头文件,描述了在C ++程序中使用name.h(C头)表单的效果。 178
在我的示例程序中,我使用
size_t
作为数组索引。虽然我得到了警告,但这确实有效。我应该这样做,并且通常会导致错误吗?
嗯,正如您猜测的那样,名称空间std
自然也是如此。
至于其余部分,有一个很好的短语:“好的建议伴随着理由”。
你应该使用std::size_t
作为索引的原因是这种类型a)向读者发出信号,表明它是一个大小或索引,b)它保证足够大。
在您的情况下,低int
,其最小保证最小值为2 15 -1将完全没问题。
另一种选择是在分配时投射到正确的类型。
答案 1 :(得分:2)
您将数组声明为
int num[num_size] = {};
这意味着它是int
的数组,其中包含10
个元素。
然后你说
for (size_t n = 0; n < num_size; ++n)
num[n] = n;
请注意,n
的类型为size_t
,即unsigned long
。因此,您将unsigned long
值放入int
数组中,因此它们会隐式转换为int
值。
答案 2 :(得分:2)
标准头文件在全局命名空间中放入了大量内容。理想情况下他们不会,但他们会这样做。通常那是因为某些东西实际上是一个宏而不是一个typedef或函数。
您有时可以在不包含标题的情况下离开,因为您包含的其他标题包含缺少的标题。
答案 3 :(得分:2)
你问:
首先,我只想确认,在使用任何cctype函数时,我必须确保包含标题,对吧?
是的,这是对的。您可能间接获得一些函数声明或其他声明,但这不是可移植代码。您应该了解标准声明声明的位置,并在使用函数,类型等之前包含该头文件。
你问:
我猜是
size_t
的相似,对吧?
是的,您应该使用std::size_t
。
有一篇与该主题相关的SO帖子。浏览Difference between size_t and std::size_t。
你问:
在这段代码中,就像我上面提到的那样,我应该使用std :: size_t吗?
在循环中,也可以使用int
。使用std::size_t
索引数组的建议是一个很好的建议,但不是不可侵犯的。
如果您选择size_t
使用n
,则可以使用static_cast
将其转换为int
以摆脱编译器警告/错误。< / p>
num[n] = static_cast<int>(n);
答案 4 :(得分:2)
我必须确保包含标题,对吧?因为,最初,我 忘了把它包括在内但它还在运行。
某些标准标头可以包含其他标头。但是,如果程序中使用了标头中的某些声明,则最好明确包含标头。它可能以这样的方式发生:在包含的头的其他实现中,不包括所需的头,编译器将发出错误。
。这是有道理的,因为它确实说它们是在...中定义的 std命名空间&#34;但我没有意识到并且没有写过它 并且没有问题。
C ++标准允许编译器将C标准函数放在全局命名空间中。虽然在这种情况下,最好明确指定名称空间std,在任何情况下都将声明函数。
至于最后一个问题,那么数组的元素具有类型int
,而你为它们分配size_t
类型的值时问题是类型int
无法容纳所有值键入size_t
,编译器会向您发出警告。您可以明确指定强制转换,以说明您知道自己在做什么的编译器。
num[n] = ( int )n;
或
num[n] = static_cast<int>( n );