C 在不编译和执行代码的情况下查找类型大小的最简单方法是什么?

C 在不编译和执行代码的情况下查找类型大小的最简单方法是什么?,c,bash,gcc,sizeof,C,Bash,Gcc,Sizeof,我编写了一个bash脚本来确定gcc的数据类型的大小(例如/sizeof int double输出int和double的相应大小),方法是将其每个参数包装在以下p()宏中,然后编译并运行代码 #define P(x) printf("sizeof(" #x ") = %u\n", (unsigned int)sizeof(x)) 问题是这相对较慢(需要一整秒钟!),尤其是链接步骤(因为使用-c或-S编译几乎不需要时间,运行输出的二进制文件也不需要时间)。一秒钟本身并没有那么慢,但如果我在其他脚

我编写了一个bash脚本来确定
gcc
的数据类型的大小(例如
/sizeof int double
输出
int
double
的相应大小),方法是将其每个参数包装在以下
p()
宏中,然后编译并运行代码

#define P(x) printf("sizeof(" #x ") = %u\n", (unsigned int)sizeof(x))
问题是这相对较慢(需要一整秒钟!),尤其是链接步骤(因为使用
-c
-S
编译几乎不需要时间,运行输出的二进制文件也不需要时间)。一秒钟本身并没有那么慢,但如果我在其他脚本中使用这个脚本,它会累加起来


有没有一种更快、更不迂回的方法来找出gcc用于数据类型的大小?

您可以使用(请参阅:
AC\u COMPUTE\u INT
)使用的“负数组大小”技巧。这样,您就不需要链接或执行代码。因此,它在交叉编译时也起作用。e、 g

int n[1 - 2 * !(sizeof(double) == 8)];
如果:
sizeof(double)!=8

缺点是,您可能必须在命令行中传递
-DCHECK_SIZE=8
或类似的命令,因为检测异常值可能需要多次传递。所以,我不确定这在总体上是否会更快,但您可能能够利用它


编辑:如果您专门使用gcc,我认为@wintermute的评论可能是最好的解决方案。

您可以仅使用gcc的预处理器实现标准类型的功能。对于标准类型,有预定义的宏:

__SIZEOF_INT__
__SIZEOF_LONG__
__SIZEOF_LONG_LONG__
__SIZEOF_SHORT__
__SIZEOF_POINTER__
__SIZEOF_FLOAT__
__SIZEOF_DOUBLE__
__SIZEOF_LONG_DOUBLE__
__SIZEOF_SIZE_T__
__SIZEOF_WCHAR_T__
__SIZEOF_WINT_T__
__SIZEOF_PTRDIFF_T__
因此,通过使用如下代码:

#define TYPE_TO_CHECK __SIZEOF_INT__
#define VAL_TO_STRING(x) #x
#define V_TO_S(x) VAL_TO_STRING(x)
#pragma message V_TO_S(TYPE_TO_CHECK)
#error "terminate"

您将能够从预处理器本身获取
\uuuuuu SIZEOF\u INT\uuuu
的值,而无需启动编译。在脚本中,您可以将
类型_TO_CHECK
(使用
-D
)定义为您需要的任何内容,并将其传递给gcc。当然,您会得到一些垃圾输出,但我相信您可以处理这些问题。

以下是三种可能的解决方案

第一个将适用于大小小于256的任何类型。在我的系统上,大约需要0.04秒(因为它不需要基本运行时以外的头或库)。一个缺点是它一次只能做一个,因为输出通道的大小很小。另一个问题是,它无法补偿某些系统(尤其是MinGW)上的慢速链接:

howbig(){
gcc-x c-使用无代码的
nm
把你的东西变成一个全局变量。
nm
可以报告它的大小

// getsize.c

struct foo {
    char str[3];
    short s;     // expect padding galore...
    int i;
} my_struct;
编译但不链接,然后使用
nm

$ gcc -c getsize.c
$ nm getsize.o --format=posix
my_struct C 000000000000000c 000000000000000c
请注意,最后一列是大小(十六进制),下面是我们如何获得它的方法:

$ nm test.o -P | cut -d ' ' -f 4
000000000000000c

# or in decimal
$ printf %d 0x`nm test.o -P | cut -d ' ' -f 4`
12

使用无代码的
objdump
如果由于某种原因,
nm
不起作用,可以将大小本身存储在全局变量中

从这个C文件开始:

// getsize.c
struct foo { char str[3]; short s; int i; };

unsigned long my_sizeof = sizeof(struct foo);
现在我们必须从对象文件中找到这个变量的值

$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o

test.o:     file format elf64-x86-64


Disassembly of section .data:

0000000000000000 <my_sizeof>:
   0:   0c 00 00 00 00 00 00 00                             ........
这将产生:

0000000000000000 <my_sizeof>:
   0:   00 00 00 00 00 00 00 0c                             ........

出于好奇,当你还没有编写和编译C代码的时候,你什么时候需要知道C类型的大小?运行一次并输出到一个文件,在需要的时候阅读该文件。我喜欢这个想法,尽管你可以只做
echo\uu SIZEOF_124;INT_124;cpp|tail-1
。这无法计算任意类型的大小tructures@EugeneSh.:可能只是因为您对填充的效果很好奇,不是吗?也许您想估算一些算法的内存消耗?谁知道呢。@Wintermute“cpp”不一定是gcc使用的相同预处理器……在某些系统上,它不是,并且可能会产生不同的结果。您可能需要“gcc-E-”代替“cpp”,你可以做到这一点,实际上它并没有那么复杂。
sizeof
是一个编译时运算符,因此如果你在文件中放入类似于
volatile const s=sizeof(struct arbStruct)的内容
,在汇编文件中,您将得到类似于:
\u:.long 16
对于我来说,这并不比我所做的快,因为它没有消除链接步骤。如果不清楚,瓶颈不是与标准库链接,而是链接器本身的调用(至少在我的系统上).A简单的
int main(){return 0;}
程序链接所用的时间与链接所用的时间一样长。@Matt很有趣。你有什么系统?我可以直接从未链接的对象文件中提取返回值,但它会有点脆弱。在这种情况下,使用cygwin的Windows。@Matt:MinGW链接速度非常慢。我添加了一个分析程序集输出的解决方案,但我不知道如何进行是的。祝你好运。这不会输出大小,它只是检查大小是否为8。@Matt-由你提供一系列值-
AC\u COMPUTE\u INT
本身执行二进制搜索以收敛到正确的值。
// getsize.c
struct foo { char str[3]; short s; int i; };

unsigned long my_sizeof = sizeof(struct foo);
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o

test.o:     file format elf64-x86-64


Disassembly of section .data:

0000000000000000 <my_sizeof>:
   0:   0c 00 00 00 00 00 00 00                             ........
// getsize.c
struct foo { char str[3]; short s; int i; };

struct __attribute__ ((scalar_storage_order("big-endian"))) {
    unsigned long v;
} my_sizeof = { sizeof(struct foo) };
0000000000000000 <my_sizeof>:
   0:   00 00 00 00 00 00 00 0c                             ........
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o |

        sed '$!d                     # keep last line only
             s/\s//g                 # remove tabs and spaces
             s/.*:\([^.]*\)\..*/\1/' # only keep between : and .'

000000000000000c