12

有人可以指出 C++ 中 sizeof 运算符的实现以及有关其实现的一些描述。

sizeof 是不能重载的运算符之一。

所以这意味着我们不能改变它的默认行为?

4

8 回答 8

25

sizeof不是 C++ 中的真正运算符。它只是插入一个等于参数大小的常量的特殊语法。sizeof不需要或没有任何运行时支持。

编辑:你想知道如何通过定义来确定类/结构的大小吗?这方面的规则是ABI的一部分,编译器只是实现它们。基本上规则包括

  1. 原始类型的大小和对齐定义;
  2. 各种指针的结构、大小和对齐方式;
  3. 在结构中打包字段的规则;
  4. 关于虚拟表相关内容的规则(更深奥)。

但是,ABI 是平台特定的,并且通常是特定于供应商的,即在 x86 和(例如)IA64 上,A下面的大小会有所不同,因为 IA64 不允许未对齐的数据访问。

struct A
{
    char i ;
    int  j ;
} ;

assert (sizeof (A) == 5)  ; // x86, MSVC #pragma pack(1)
assert (sizeof (A) == 8)  ; // x86, MSVC default
assert (sizeof (A) == 16) ; // IA64
于 2009-04-05T13:00:38.590 回答
15

http://en.wikipedia.org/wiki/Sizeof

基本上,引用Bjarne Stroustrup 的 C++ FAQ

Sizeof 不能重载,因为内置操作,例如将指针递增到数组中隐式依赖于它。考虑:

X a[10];
X* p = &a[3];
X* q = &a[3];
p++;    // p points to a[4]
    // thus the integer value of p must be
    // sizeof(X) larger than the integer value of q

因此,程序员不能在不违反基本语言规则的情况下赋予 sizeof(X) 新的不同含义。

于 2009-04-05T12:58:05.213 回答
8

不,你不能改变它。你希望从看到它的实现中学到什么?

sizeof使用更基本的操作无法用 C++ 编写什么。它不是函数,也不是库头文件的一部分,例如printf,或malloc. 它在编译器内部。

编辑:如果编译器本身是用 C 或 C++ 编写的,那么您可以认为实现是这样的:

size_t calculate_sizeof(expression_or_type)
{
   if (is_type(expression_or_type))
   {
       if (is_array_type(expression_or_type))
       {
           return array_size(exprssoin_or_type) * 
             calculate_sizeof(underlying_type_of_array(expression_or_type));
       }
       else
       {
           switch (expression_or_type)
           {
                case int_type:
                case unsigned_int_type:
                     return 4; //for example
                case char_type:
                case unsigned_char_type:
                case signed_char_type:
                     return 1;
                case pointer_type:
                     return 4; //for example

                //etc., for all the built-in types
                case class_or_struct_type:
                {
                     int base_size = compiler_overhead(expression_or_type);
                     for (/*loop over each class member*/)
                     {
                          base_size += calculate_sizeof(class_member) +
                              padding(class_member);
                     }
                     return round_up_to_multiple(base_size,
                              alignment_of_type(expression_or_type));
                }
                case union_type:
                {
                     int max_size = 0;
                     for (/*loop over each class member*/)
                     {
                          max_size = max(max_size, 
                             calculate_sizeof(class_member));
                     }
                     return round_up_to_multiple(max_size,
                            alignment_of_type(expression_or_type));
                }
           }
       }
   }
   else
   {
       return calculate_sizeof(type_of(expression_or_type));
   }
}

请注意,这是非常伪代码。有很多我没有包括在内的东西,但这是一般的想法。编译器可能实际上并没有这样做。它可能会计算一个类型(包括一个类)的大小并存储它,而不是每次编写时都重新计算sizeof(X)。例如,也允许指针根据它们所指向的内容而具有不同的大小。

于 2009-04-05T13:01:24.533 回答
5

sizeof 做它在编译时所做的事情。运算符重载只是函数,它们在运行时执行它们所做的事情。因此,即使 C++ 标准允许,也无法重载 sizeof。

于 2009-04-05T13:06:28.670 回答
3

sizeof 是一个编译时运算符,这意味着它是在编译时计算的。

它不能被重载,因为它已经对所有用户定义的类型都有意义——类的 sizeof() 是类定义的对象在内存中的大小,而变量的 sizeof() 是对象的大小变量名占用内存。

于 2009-04-05T13:08:29.133 回答
1

除非您需要查看 C++ 特定大小的计算方式(例如 v-table 的分配),否则您可以查看 Plan9 的 C 编译器。这比尝试解决 g++ 简单得多。

于 2009-04-05T14:58:26.313 回答
1

多变的:

#define getsize_var(x) ((char *)(&(x) + 1) - (char *)&(x))

类型:

#define getsize_type(type) ( (char*)((type*)(1) + 1) - (char*)((type *)(1)))
于 2010-06-07T17:20:06.673 回答
-1

查看Gnu C++ 编译器的源代码,了解实际情况是如何完成的。

于 2009-04-05T14:29:58.330 回答