`sizeof` *真的*评估为`std :: size_t`吗?它可以?

时间:2013-12-27 22:51:52

标签: c++ c++11 std language-lawyer

采取以下标准段落:

  

[C++11: 5.3.3/6]: sizeofsizeof...的结果是std::size_t类型的常量。 [注意: std::size_t在标准标题<cstddef>(18.2)中定义。 -end note]

现在:

  

[C++11: 18.2/6]:类型size_t是一个实现定义的无符号整数类型,其大小足以包含任何对象的字节大小。

当然,该段落并不要求size_t是使用typedef定义的类型别名,但由于明确声明标准标题<cstddef>可用,因此我认为我们可以理解为,如果不包含<cstddef>,则应删除size_t对程序可用的任何保证。

然而,根据第一个引用,我们可以获得std::size_t类型的表达式。

We can actually demonstrate both of these facts

int main()
{
    typedef decltype(sizeof(0)) my_size_t;

    my_size_t x   = 0;  // OK
    std::size_t y = 1;  // error: 'size_t' is not a member of 'std'
}
程序看不到

std::size_t,但sizeof(0)仍然给我们一个?真的?

因此5.3.3/6 有缺陷并且它实际上具有“与std::size_t解析为的相同类型”是不正确的,但是 std::size_t本身?

当然,如果std::size_t是一个类型别名,那么这两个是同一个,但同样,实际上并不需要它。

5 个答案:

答案 0 :(得分:52)

标准只是要求sizeof(expr)的类型与std::size_t的类型相同。没有授权使用sizeof(expr)使名称std::size_t可用,并且由于std::size_t只是命名其中一个内置整数类型,因此没有真正的问题。

答案 1 :(得分:46)

不要混淆地图的地图。

类型可以通过类型名称命名。这些类型名称可以是内置的,也可以是用户定义的类型,或者它们甚至可以是template参数,并根据实例化引用多种不同的类型。

但名字不是类型。显然,标准并不要求所有类型都有名称 - 经典struct {}是一种没有名称的类型。

std::size_t是一个类型名称。它命名sizeof(expression)返回的类型。

编译器可以具有该类型的规范名称 - __size_t将是一种具有唯一内置规范类型名称的方式。

该条款中的标准保证,无论sizeof(expression)的类型是什么,一旦#include <cstddef>,名称std::size_t现在引用该类型。

在标准中,它们按名称引用类型。他们没有说&#34;这个类型名称引用的类型&#34;,而只是说&#34;类型$ NAME $&#34;。如果需要,编译器可以决定int__int_32_fast的另一个名称,标准也没有异议。

同样的事情发生在std::nullptr_tstd::initializer_list<Ts>以及std::type_info上:使用这些类型的变量并不总是要求包含为这些类型提供名称的标题在你的程序中。

传统的C / C ++内置类型都具有不需要标头的规范名称。缺点是这会破坏现有代码,因为全局范围中的新类型名称会与其他标识符冲突。

通过使用&#34;无名类型&#34;,您可以通过包含头文件获取其名称,我们可以避免这个问题。

答案 2 :(得分:5)

据我了解,此标准段落需要以下表达式:

typeid(sizeof(0)) == typeid(std::size_t)

总是会产生true。如果您使用实际标识符std::size_t::size_t或任何其他别名/ typedef将无关紧要,只要保留类型的标识(根据std::typeinfo::operator==())。

相同的类型标识问题出现在该语言的其他位置。例如,在我的64位机器中,由于函数重新定义,以下代码无法编译:

#include <cstddef>
void foo(std::size_t x)
{}

void foo(unsigned long x)
{}

答案 3 :(得分:5)

sizeof产生的类型是一些无符号整数类型;实现定义了它是哪一个。

例如,在某些特定实现中,sizeof表达式的类型可能为unsigned long

std::size_t,如果它是typedef,只不过是unsigned long的替代名称。所以这两个陈述:

  

sizeof ...的类型是unsigned long

类型的常量

  

sizeof ...的类型是std::size_t

类型的常量

对于该实现说的是完全相同的。类型unsigned long和类型std::size_t属于同一类型。不同之处在于后者对所有(符合标准)实现都是准确的,其中std::size_t可能是unsigned int或其他一些无符号类型的别名。

就编译器而言,sizeof产生类型为unsigned long的结果;编译器(与运行时库相对)不需要知道名称size_t

这一切都假设std::size_t(或者只是size_t,如果你在谈论C)是一个typedef。这在C或C ++标准中都没有说明。然而,通过使size_t成为typedef,实现可以直接符合标准的要求。我不相信有任何其他便携式方式来满足这些要求。 (它不能是宏或实现定义的关键字,因为它会侵犯用户的名称空间,并且宏不会限定在std命名空间内。)编译器可以 make size_t除了typedef之外的一些特定于实现的构造,但由于typedef工作得非常好,所以没有必要这样做。如果标准声明size_t是一个typedef,那将是很好的,恕我直言。

(一个无关紧要的旁边:真正的问题是标准将结果称为“常量”。在ISO C中,“常量”是一个标记,例如整数文字.C ++,据我所知,没有定义名词“常量”,但它确实引用了术语的ISO C定义。sizeof ...是一个常量表达式;它不是常量。调用结果“常量值”是合理的。)

答案 4 :(得分:2)

它是相同的类型,但您必须包含该标头才能使用它。