sizeof 是在编译时还是运行时评估?

Posted

技术标签:

【中文标题】sizeof 是在编译时还是运行时评估?【英文标题】:Does sizeof evaluate at compile-time or runtime? 【发布时间】:2012-06-26 03:12:07 【问题描述】:

我对@9​​87654321@运营商的评估时间感到困惑。 sizeof 运算符何时被评估?

它的评估时间(编译时或运行时)是否取决于语言(C?C++?)?

如果在 C++ 中运行时创建的对象,我们可以使用sizeof 吗?

【问题讨论】:

【参考方案1】:

在 C 中它并不总是一个编译时操作,如下代码所示:

#include <stdio.h>
#include <stdint.h>

int main(void) 
    int x;
    scanf("%d", &x);   // Value X is not known until run-time
    
    uint16_t data[x];  // VLA: has flexible size depending on input
    
    printf("Value x is: %d\nSize is: %zu\n", x, sizeof(data));
    // sizeof produces proper results at runtime
    
    return 0;

数组data的大小直到运行时才知道,sizeof操作符仍然可以正常工作。

这是 C++ 选择不支持 VLA 的几个原因之一。

【讨论】:

【参考方案2】:

编译时间,因为它是在编译时计算大小。“编译时间”是您构建代码的时间——编译器将您的源代码转换为 IL 的时间。

【讨论】:

【参考方案3】:

几乎总是编译时间。但您可能会对以下示例感兴趣:

char c[100];
sizeof(c); // 100

char* d = malloc(100);
sizeof(d); //probably 4 or 8.  tells you the size of the pointer!

BaseClass* b = new DerivedClass();
sizeof(b); //probably 4 or 8 as above.

void foo(char[100] x) 
    sizeof(x); //probably 4 or 8.  I hate this.  Don't use this style for this reason.


struct Foo 
    char a[100];
    char b[200];
;

sizeof(struct Foo); //probably 300.  Technically architecture dependent but it will be
//the # of bytes the compiler needs to make a Foo.

struct Foo foo;
sizeof(foo); //same as sizeof(struct Foo)

struct Foo* fooP;
sizeof(fooP); //probably 4 or 8

class ForwardDeclaredClass;

ForwardDeclaredClass* p;
sizeof(p); //4 or 8
ForwardDeclaredClass fdc; //compile time error.  Compiler
//doesn't know how many bytes to allocate

sizeof(ForwardDeclaredClass); //compile time error, same reason

【讨论】:

也许“void foo(char[100] x)”实际上应该是“void foo(char x[100])”? VLA 怎么样?【参考方案4】:

在几乎所有情况下,sizeof 的评估都是基于静态类型信息(基本上是在编译时)。

C99 的可变长度数组 (VLA) 是一个例外(我认为是唯一一个)。

【讨论】:

很好地证明了 VLA 是多么荒谬的变态。恕我直言,显式可变长度堆栈消耗(alloca)要好得多。 @valdo,我看不出这应该证明什么。 sizeof 在执行时动态调整大小的对象必须在执行时进行评估似乎很正常。与alloca(甚至没有标准化且没有范围)或malloc等其他机制相比,两者都不知道他们创建的对象的大小并不是很有帮助。 @Jens Gustedt:抱歉,我的意思是 example,而不是 proofalloca 不需要明确的释放/范围。生成的代码(或多或少)与 VLA 相同 - 移动堆栈指针 + 在跨页边界时探测堆栈内存。我个人在元编程(temapltes 等)中非常积极地使用sizeof,我想100% 确定sizeof 中的任何内容都不会在运行时被评估。 @valdo,不需要释放范围,但也没有提供。我发现分配一直持续到函数终止的想法非常违反直觉。我在 C 中使用宏进行了很多元编程,到目前为止,我还没有因为 VLA 而遇到过大问题。并且不要夸大 VLA 的 sizeof 的运行时方面。它只是对一些包含大小的隐藏变量的评估。但是编译器正在为您完成工作,并且可以在许多地方进行优化。 @Jens Gustedt:alloca 不提供“释放范围”,原因与 VLA 不提供此功能完全相同。在不影响随后分配的堆栈变量的情况下,可能不会释放堆栈变量(固定大小或非固定大小)。所以你说持续到函数终止的(显式)分配是违反直觉的,OTOH我相信强制编译时运算符在运行时默默地做事情是违反直觉的。它不仅仅是一个“隐藏变量”,有时这个变量需要评估。比如函数调用的 retval 的sizeof(不正常调用)。

以上是关于sizeof 是在编译时还是运行时评估?的主要内容,如果未能解决你的问题,请参考以下文章

nameof() 是在编译时评估的吗?

jquery click函数声明在运行时评估变量

python 模型运行时评估

Django:让 ModelChoiceField 在运行时评估查询集

将变量转换为Scala“运行时评估”中的方法

常量和编译时评估 - 为啥要改变这种行为