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

如何在C中的编译时打印sizeof()的结果?,c,sizeof,compile-time,C,Sizeof,Compile Time,如何在C中的编译时打印sizeof()的结果 现在,我使用静态断言(基于其他web资源自制)将sizeof()结果与各种常量进行比较。虽然这有效。。。它既不优雅也不快速。我还可以创建变量/struct的实例并查看映射文件,但这也不如直接调用/command/operator优雅和快速。此外,这是一个使用多个交叉编译器的嵌入式项目。。。因此,构建一个示例程序并将其加载到目标中,然后读取一个值,这比上述两种方法都要麻烦 在我的例子(旧GCC)中,#warning sizeof(MyStruct)在打

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

现在,我使用静态断言(基于其他web资源自制)将sizeof()结果与各种常量进行比较。虽然这有效。。。它既不优雅也不快速。我还可以创建变量/struct的实例并查看映射文件,但这也不如直接调用/command/operator优雅和快速。此外,这是一个使用多个交叉编译器的嵌入式项目。。。因此,构建一个示例程序并将其加载到目标中,然后读取一个值,这比上述两种方法都要麻烦


在我的例子(旧GCC)中,
#warning sizeof(MyStruct)
在打印警告之前实际上不会解释sizeof()。

不能这样做,不能使用结构。预处理器在编译之前被调用,因此甚至没有结构的概念;无法评估不存在/未定义的对象的大小。预处理器确实对转换单元进行标记化,但它这样做只是为了定位宏调用

最接近的方法是依赖于一些实现定义的宏,这些宏的计算结果与内置类型的大小相当。在gcc中,您可以找到具有以下特性的:

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

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

我正在四处寻找类似的功能,突然发现:

这让我产生了这样的想法:

char (*__kaboom)[sizeof( YourTypeHere )] = 1;
这导致VS2015中出现以下警告:

warning C4047: 'initializing': 'DWORD (*)[88]' differs in levels of indirection from 'int'
在这种情况下,88是您要找的尺寸

超级黑客,但它做到了。可能晚了几年,但希望这对某些人有用

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

编辑:为clang 3.6开箱即用

我能为GCC使用的唯一技巧是滥用
-Wformat
,并让宏定义如下函数:

void kaboom_print( void )
{
    printf( "%d", __kaboom );
}
这会给你一个警告,比如:

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

比最初的建议稍微粗俗一点,但也许对gcc稍有了解的人可以想出一个更好的滥用警告。

Duplicate
case
constant是一个保证在所有C编译器中都能工作的技巧,不管每个编译器如何报告错误。对于Visual C++,它是简单的:

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 started: Project: cpptest, Configuration: Debug Win32 ------
 cpptest.cpp c:\work\cpptest\cpptest\cpptest.cpp(29): error C2196: case value '48' already used
 ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
所以结构X的大小是48

编辑(2020年6月3日): 对于只打印“重复大小写值”的gcc或任何其他编译器,我使用以下技巧缩小值的范围:

1) 添加一个case值1==2(表示false)

2) 通过反复试验,缩小数值范围,例如,我尝试猜测
sizeof(X)
is>16:

#include <stdio.h>
typedef struct _X {
    int a;
    char b[10];
} X;
int main()
{
    printf("Hello World");

    int dummy=0   ;
    switch (dummy) {
    case  1==2:
    case sizeof( X)>16:
    //case 16:
    break;
    }
    return 0;
}

因此它是错误的,即sizeof(X)我偶然发现了一个类似于的解决方案,而这个解决方案产生了一个不太详细的警告,因此您可能会发现它很有用:

char (*__fail)(void)[sizeof(uint64_t)] = 1;
这将生成错误消息

Function cannot return array type 'char [8]'

这是用最新版本的
clang(1)

测试的。我的gcc编译器拒绝使用上述任何解决方案打印大小。我颠倒了逻辑,为它的大小注入编译器警告

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件


嗯。。。这是一个选项。

虽然这并不完全是在编译时,但它是在运行时之前,所以它可能仍然与某些人相关

可以这样定义数组:

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
还有一种方法(实际可行):

使用旧版gcc 5.x。产生如下错误:

a.c:8:54: error: initializer element is not computable at load time
a.c:8:54: note: (near initialization for 'a[8]')

p、 显然,这一个是(非常)gcc特定的。所有其他方法对我都不起作用。

以下方法适用于GCC、Clang、MSVC等,甚至在旧版本中,都是基于函数参数从指针到数组到标量类型的转换失败。编译器不会打印数组的大小,因此您可以从输出中获取值。在C和C++模式下工作。 查找
sizeof(long)
()的示例代码:

相关输出的示例:

  • 通用条款4.4.7
:1:注意:应为“int”,但参数类型为“char(*)[8]”

  • 叮当3.0.0
:1:6:注意:候选函数不可行:第一个参数没有从'char(*)[8]'到'int'的已知转换

  • MSVC 19.14
(2):警告C4047:“函数”:“int”与“char(*)[4]”的间接寻址级别不同。

@jws 好主意!。但是,sizeof(xxx)是一个常量表达式(除了VLA,),因此sizeof运算符即使在案例选择中也应该起作用:

enum e1 {dummy=-1};
enum e1 ev;
switch (ev) {
    case sizeof(myType):;
    break;
    default:;
}

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

这是任何c编译器的通用解决方案

我意识到,如果我们的目标是知道
sizeof()
的值,而不是打印它的值,那么我们只需要计算几个编译时
sizeof(X)>?
表达式来缩小值

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

许多标准C结构可以实现我们的目标。我单独描述的重复
案例
值技巧就是其中之一。另一种方法是通过测试初始化器中的零除法,编译器在编译时对初始化器求值。例如,要获得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: In function ‘main’:
main.c:14:5: error: duplicate case value
     case sizeof( X)>10:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:15:5: error: duplicate case value
     case sizeof( X)>12:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:16:5: error: duplicate case value
     case sizeof( X)>14:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:17:5: error: duplicate case value
     case sizeof( X)>16:
     ^~~~
main.c:12:5: error: previously used here
     case  1==2:
     ^~~~
main.c:18:5: error: duplicate case value
     case  sizeof( X)==16:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
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);
        ^
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 ==========
结果

main.c: In function ‘main’:
main.c:14:5: error: duplicate case value
     case sizeof( X)>10:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:15:5: error: duplicate case value
     case sizeof( X)>12:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:16:5: error: duplicate case value
     case sizeof( X)>14:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:17:5: error: duplicate case value
     case sizeof( X)>16:
     ^~~~
main.c:12:5: error: previously used here
     case  1==2:
     ^~~~
main.c:18:5: error: duplicate case value
     case  sizeof( X)==16:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
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);
        ^
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)
是对我有效的快速简单的解决方案(GCC):

(char[sizeof(long)])“bla”;
这将导致显示以下错误消息:
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);
        ^
#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);
        ^
#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 ==========
//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;
}
ISO C++ forbids casting to an array type 'char [8]'