如何在C中编译时打印sizeof()的结果?

时间:2014-01-07 18:57:27

标签: c sizeof compile-time

如何在编译时以C?

打印sizeof()的结果

目前我正在使用静态断言(基于其他Web资源自制)来将sizeof()结果与各种常量进行比较。虽然这有效但它远非优雅或快速。我还可以创建变量/ struct的实例并查看映射文件,但这比直接调用/命令/运算符更不优雅和快速。此外,这是一个使用多个交叉编译器的嵌入式项目...因此,为目标构建和加载示例程序然后读出一个值比上述任何一个都更麻烦。

在我的情况下(旧的GCC),#warning sizeof(MyStruct)在打印警告之前实际上并不解释sizeof()。

12 个答案:

答案 0 :(得分:42)

当我偶然发现这个时,我正在寻找类似的功能:

Is it possible to print out the size of a C++ class at compile-time?

这给了我这个想法:

char (*__kaboom)[sizeof( YourTypeHere )] = 1;

这导致VS2015中出现以下警告:

warning C4047: 'initializing': 'DWORD (*)[88]' differs in levels of indirection from 'int'

这种情况下88就是你要找的尺寸。

超级hacky,但它确实可以解决问题。可能要晚了几年,但希望这对某人有用。

我还没有机会尝试使用gcc或clang,但是如果有人在我之前找不到它,我会尝试确认它是否有效。

编辑:开箱即用,适用于clang 3.6

我可以为GCC工作的唯一技巧是滥用-Wformat并让宏定义如下函数:

void kaboom_print( void )
{
    printf( "%d", __kaboom );
}

这会给你一个警告:

...blah blah blah... argument 2 has type 'char (*)[88]'

比原来的建议稍微粗略一点,但也许知道gcc好一点的人可以想出更好的警告来滥用。

答案 1 :(得分:6)

所有你需要的是一个技巧,导致编译器抱怨一些编译时整数值被错误地使用,比如重复的case常量:

struct X {
    int a,b;
    int c[10];
};
int _tmain(int argc, _TCHAR* argv[])
{
    int dummy;

    switch (dummy) {
    case sizeof(X):
    case sizeof(X):
        break;
    }
    return 0;
}
  

------ Build build:Project:cpptest,Configuration:Debug Win32 ------ cpptest.cpp c:\ work \ cpptest \ cpptest \ cpptest.cpp(29):error C2196:case value '48'已经使用过   ==========构建:0成功,1个失败,0个最新,0个跳过==========

因此结构X的大小为48

答案 2 :(得分:4)

另一种方式(实际可行):

val errorTV = findViewById<TextView>(R.id.textinput_error)
errorTV.updatePadding(top = 4)

适用于较旧的gcc5.x。产生这样的错误:

char __foo[sizeof(MyStruct) + 1] = {[sizeof(MyStruct)] = ""};

p.s。显然,这是(非常)gcc特定的。其他所有方法都不适合我。

答案 3 :(得分:2)

以下方法可在GCC,Clang,MSVC等环境中使用,即使在较旧的版本中也是如此,它是基于将函数参数从指针到数组转换为标量类型的失败。编译器会打印数组的大小,因此您可以从输出中获取值。在C和C ++模式下均可使用。

找出sizeof(long)play with it online)的示例代码:

char checker(int);
char checkSizeOfInt[sizeof(long)]={checker(&checkSizeOfInt)};

相关输出示例:

  • GCC 4.4.7
  

<source>:1: note: expected 'int' but argument is of type 'char (*)[8]'

  • c 3.0.0
  

<source>:1:6: note: candidate function not viable: no known conversion from 'char (*)[8]' to 'int' for 1st argument;

  • MSVC 19.14
  

<source>(2): warning C4047: 'function': 'int' differs in levels of indirection from 'char (*)[4]'

答案 4 :(得分:2)

//main.cpp
#include <cstddef>
template <std::size_t x>
struct show_size;

void foo()
{
    show_size<sizeof(my_type)>();//!!please change `my_type` to your expected
}

int main()
{
    return 0;
}

您可以编译这段非常简单的代码,并且在其预编译阶段,编译器将给出错误,其中sizeof(my_type)将给出具体值。例如:

g++ main.cpp

答案 5 :(得分:0)

我偶然发现了一个类似于Bakhazard great solution的解决方案,而且这个解决方案会产生一个不那么详细的警告,所以你可能会发现它很有用:

char (*__fail)(void)[sizeof(uint64_t)] = 1;

这会产生错误消息

Function cannot return array type 'char [8]'

使用最新版本的clang(1)进行测试。

答案 6 :(得分:0)

我的gcc C编译器拒绝使用上述任何解决方案来打印大小。我倒置了逻辑来注入编译器警告,警告它不是什么大小。

enum e
{
    X = sizeof(struct mystruct)
};

void foo()
{
    static enum e ev;

    switch (ev)
    {
    case 0:
    case 4:
    case 8:
    case 12:
    case 16:
    case 20:
        break;
    }
}

然后我必须仔细阅读警告,以防丢失号码。

warning: case value '0' not in enumerated type 'e' [-Wswitch]
warning: case value '4' not in enumerated type 'e' [-Wswitch]
warning: case value '12' not in enumerated type 'e' [-Wswitch]
warning: case value '16' not in enumerated type 'e' [-Wswitch]
warning: case value '20' not in enumerated type 'e' [-Wswitch]

所以我的结构大小是8。

我的包装是4。

嗯...这是一个选择。

答案 7 :(得分:0)

尽管这并非完全在编译时,但它在运行时之前是 ,因此它对某些人来说仍然有意义。

您可以这样定义一个数组:

uint8_t __some_distinct_name[sizeof(YourTypeHere)];

然后,在编译之后,从目标文件中获取大小:

$ nm -td -S your_object_file |       # list symbols and their sizes, in decimal
  grep ' __some_distinct_name$' |    # select the right one
  cut -d' ' -f2 |                    # grab the size field
  xargs printf "Your type is %d B\n" # print

答案 8 :(得分:0)

@jws 好主意!。但是,sizeof(xxx)是一个常量表达式(VLA,https://en.cppreference.com/w/c/language/sizeof除外),因此,即使在选择大小写的情况下,sizeof运算符也应该起作用:

class TooMany a where
  tooMany :: a -> Bool

newtype Baz = Baz (a, a) deriving (Eq, Show)

instance TooMany Baz where
  tooMany (Baz (n, _)) = n > 42

..它在我的GCC中工作:“ .. \ WinThreads.c:18:9:警告:案例值'4'不在枚举类型'enum e1'[-Wswitch]”

答案 9 :(得分:0)

这是所有C编译器的通用解决方案。

我已经意识到,如果我们的目标是了解 sizeof()的值,而不是 printing 的值,那么我们只需要评估一个很少的编译时sizeof(X)>??表达式来缩小值。

诀窍是当表达式的计算结果为false(零)或true(非零)时,会产生编译时错误。

许多标准C构造都可以实现我们的目标。我分别描述的重复case值技巧是其中之一。另一个是通过初始化程序测试除零,编译器在编译时对其进行评估。例如,要获取X的大小:

struct _X {
  int a;
  char c;
  double d;
  float f[30];
} X;

编译几行:

#include <stdio.h>
struct _X {
  int a;
  char c;
  double d;
  float f[30];
} X;
int r2=1/(sizeof(X)<170);
int r3=1/(sizeof(X)<100);
int r4=1/(sizeof(X)<80);
int r5=1/(sizeof(X)<60);
int main()
{
   return 0;
}

结果

main.c:17:9: warning: division by zero [-Wdiv-by-zero]
 int r3=1/(sizeof(X)<100);
         ^
main.c:17:8: error: initializer element is not constant
 int r3=1/(sizeof(X)<100);
        ^
main.c:18:9: warning: division by zero [-Wdiv-by-zero]
 int r4=1/(sizeof(X)<80);
         ^
main.c:18:8: error: initializer element is not constant
 int r4=1/(sizeof(X)<80);
        ^
main.c:19:9: warning: division by zero [-Wdiv-by-zero]
 int r5=1/(sizeof(X)<60);
         ^
main.c:19:8: error: initializer element is not constant
 int r5=1/(sizeof(X)<60);
        ^

隐含sizeof(X)<170true(非零),但sizeof(X)<100false(在编译时除以零)。然后,我们可以通过使用其他一些值重复测试来获得实际值。例如

#include <stdio.h>
struct _X {
  int a;
  char c;
  double d;
  float f[30];
} X;
int r2=1/(sizeof(X)<140);
int r3=1/(sizeof(X)<137);
int r4=1/(sizeof(X)<136);
int r5=1/(sizeof(X)!=136);

int main()
{
    return 0;
}

结果

main.c:18:9: warning: division by zero [-Wdiv-by-zero]
 int r4=1/(sizeof(X)<136);
         ^
main.c:18:8: error: initializer element is not constant
 int r4=1/(sizeof(X)<136);
        ^
main.c:19:9: warning: division by zero [-Wdiv-by-zero]
 int r5=1/(sizeof(X)!=136);
         ^
main.c:19:8: error: initializer element is not constant
 int r5=1/(sizeof(X)!=136);
        ^

因此我们知道sizeof(X)==136

或者,通过使用?:运算符,我们可以使用更多在编译时评估的C语言构造。使用数组声明的Visual C ++示例:

#include "stdafx.h"
struct X {
  int a;
  char b[30];
  double d;
  float f[20];
};
int a1[sizeof(X)<130?-1:1];
int a2[sizeof(X)<120?1:-1];
int a3[sizeof(X)==128?-1:1];

int _tmain(int argc, _TCHAR* argv[]){
  return 0;
}

结果

1>------ Build started: Project: cpptest, Configuration: Release Win32 ------
1>  cpptest.cpp
1>cpptest.cpp(11): error C2118: negative subscript
1>cpptest.cpp(12): error C2118: negative subscript
1>cpptest.cpp(13): error C2118: negative subscript
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

暗示sizeof(X)是<130,而不是<120,等于128

答案 10 :(得分:0)

适用于我的快速简单的解决方案(GCC):

@bot.event
async def on_message(message):
    if message.channel.id in cmdchannels :
        await message.delete()
    await bot.process_commands(message)

这会导致显示一条错误消息,显示(char[sizeof(long long)])"bla"; 的大小:

long long

答案 11 :(得分:-4)

你不能这样做,不能用结构。在编译发生之前调用预处理器,因此甚至没有结构的概念;你不能评估不存在/未定义的东西的大小。预处理器 标记了一个翻译单元,但它只是为了定位宏调用。

最接近的是依靠一些实现定义的宏来评估内置类型的大小。在gcc中,您可以找到以下内容:

gcc -dM -E - </dev/null | grep -i size

在我的系统中打印过:

#define __SIZE_MAX__ 18446744073709551615UL
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __SIZEOF_LONG__ 8
#define __SIZEOF_LONG_DOUBLE__ 16
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __SIZE_TYPE__ long unsigned int
#define __SIZEOF_PTRDIFF_T__ 8
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_INT128__ 16
#define __SIZEOF_WCHAR_T__ 4
#define __SIZEOF_DOUBLE__ 8
#define __SIZEOF_LONG_LONG__ 8

如果不编写程序并执行它,就无法知道自定义结构的大小。