C++编译报错求助:sizeof(rs_comm().ab[0])错误及解决方案原理咨询
sizeof(((rs_comm*)0)->ab[0])的原理 问题背景
你在编译xdn-project/digitalnote项目的./src/crypto/crypto.cpp第338行时遇到了如下错误:
error: value-initialization of incomplete type ‘Crypto::rs_comm:: []’
对应的出错代码是:
return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]);
你找到的修复代码来自cryptonotefoundation/cryptonote:
return sizeof(rs_comm) + pubs_count * sizeof(((rs_comm*)0)->ab[0]);
下面详细解释这个修复的原理,尤其是你疑惑的sizeof(((rs_comm*)0)->ab[0])部分。
原代码出错的原因
原代码中rs_comm().ab[0]试图创建一个rs_comm类型的临时对象,然后访问它的数组成员ab的第一个元素,再获取该元素的大小。但编译报错的核心原因是:
- 当前编译上下文中,
Crypto::rs_comm是一个不完整类型(比如仅做了前向声明class rs_comm;,而完整的类定义在当前编译单元中不可见)。 - C++中,创建一个类的临时对象(如
rs_comm())需要编译器知道类的完整定义(包括大小、构造函数等信息),否则无法完成值初始化,因此触发“不完整类型的值初始化”错误。
修复代码的原理详解
修复代码的关键在于sizeof(((rs_comm*)0)->ab[0]),这是C++中一种常用的编译期技巧,核心利用了**sizeof运算符不需要实际求值**的特性:
拆解每一部分含义
(rs_comm*)0:
把常量0强制转换为rs_comm*类型的指针(空指针)。这里不需要实际存在的rs_comm对象,因为我们不会真的去访问这个指针指向的内存。->ab[0]:
通过这个空指针访问rs_comm类的成员数组ab的第一个元素。注意:这里不会触发实际的内存访问(因为sizeof是编译期计算的),编译器仅仅是解析这个表达式的静态类型——也就是ab[0]的类型是什么。sizeof(...):
计算上述表达式的静态类型的大小。因为sizeof在编译阶段就完成计算,只需要知道类型信息,不需要运行时的对象实例,所以即使使用了空指针,也不会导致空指针引用的运行时错误。
为什么这个方法能解决问题?
相比原代码需要创建rs_comm临时对象(依赖完整类定义),修复代码完全绕开了对象的创建:
- 它只需要
rs_comm的前向声明(编译器知道这是一个类类型),以及成员ab的类型信息(编译器能通过类定义的可见性或头文件中的声明得知ab是一个数组,以及数组元素的类型)。 - 编译期就能计算出
ab[0]的大小,不需要运行时的对象实例。
给Java开发者的类比
如果你熟悉Java,可以这样理解:
- Java中要获取类成员的类型大小,通常需要通过反射(运行时操作);
- 而C++的
sizeof是编译期运算符,直接基于静态类型计算大小,这个空指针技巧就是利用编译期特性,在不创建对象的前提下获取成员的类型大小。
内容的提问来源于stack exchange,提问作者Ernestas Gruodis

