如何在预处理器宏中使用“sizeof”?

时间:2010-11-02 15:32:50

标签: c gcc

有没有办法在预处理器宏中使用sizeof

例如,多年来我有很多情况需要做以下事情:

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

我在这里检查的确切内容是完全弥补的 - 重点是,我经常喜欢在这些类型的(大小或对齐)编译时检查中防止某人修改可能导致错位的数据结构或重新调整会破坏它们的东西。

毋庸置疑 - 我似乎无法以上述方式使用sizeof

13 个答案:

答案 0 :(得分:67)

  

无论如何在预处理器宏中使用“sizeof”吗?

没有。条件指令采用一组受限的条件表达式; sizeof是不允许的事情之一。

在解析源之前(至少在概念上)评估预处理指令,因此还没有任何类型或变量可以获得它们的大小。

但是,有一些技术可以在C中获得编译时断言(例如,参见this page)。

答案 1 :(得分:53)

有几种方法可以做到这一点。 如果sizeof(someThing)等于PAGE_SIZE,则以下代码段不会产生代码;否则会产生编译时错误。

1。 C11方式

从C11开始,您可以使用static_assert(需要#include <assert.h>)。

用法:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2。自定义宏

如果您只想在sizeof(something)不符合预期时遇到编译时错误,可以使用以下宏:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

用法:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

This article详细解释了它的工作原理。

3。 MS特定的

在Microsoft C ++编译器上,您可以使用C_ASSERT宏(需要#include <windows.h>),它使用类似于第2节中描述的技巧。

用法:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);

答案 2 :(得分:9)

我知道这个帖子真的很旧但是......

我的解决方案:

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

只要该表达式等于零,它就可以很好地编译。还有别的东西,就在那里爆炸了。因为变量是extern'd,所以它不会占用空间,只要没有人引用它(它们不会引用它),它就不会导致链接错误。

不像assert宏那样灵活,但是我无法在我的GCC版本中编译,这将......而且我认为它将在任何地方编译。

答案 3 :(得分:7)

我知道这是一个迟到的答案,但要添加到Mike的版本,这是我们使用的不分配任何内存的版本。我没有拿出原始尺寸检查,我几年前在互联网上找到它,不幸的是无法引用作者。另外两个只是同一个想法的延伸。

因为它们是typedef,所以没有分配任何东西。使用名称中的__LINE__,它始终是一个不同的名称,因此可以在需要时复制和粘贴它。这适用于MS Visual Studio C编译器和GCC Arm编译器。它在CodeWarrior中不起作用,CW抱怨重新定义,而不是使用__LINE__预处理器结构。

Sub InsertShapeRange()

Dim my_row As Integer
Dim my_col As Integer
Dim Rng As Range
Dim shp As Shape
Dim ws As Worksheet

my_col = Application.InputBox("No. of x dies?", "Wafer Map", Default:=0)
my_row = Application.InputBox("No. of y dies?", "Wafer Map", Default:=0)

Set Rng = Selection
Set Rng = Rng.Resize(my_row, my_col)
Set ws = Rng.Parent
Set shp = ws.Shapes.AddShape(1, Rng.Left, Rng.Top, Rng.Width, Rng.Height)
With shp
    .Fill.Visible = msoFalse
    With .Line
        .Visible = msoTrue
        .ForeColor.RGB = RGB(0, 0, 0)
        .Transparency = 0
    End With
End With
With Rng
    .Borders(xlInsideHorizontal).LineStyle = xlContinuous
    .Borders(xlInsideVertical).LineStyle = xlContinuous
End With 
End Sub

答案 4 :(得分:4)

下一个宏怎么样:

/* 
 * Simple compile time assertion.
 * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
 */
#define CT_ASSERT(exp, message_identifier) \
    struct compile_time_assertion { \
        char message_identifier : 8 + !(exp); \
    }

例如在评论中,MSVC告诉我们:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits

答案 5 :(得分:3)

现有的答案只是展示了如何根据类型的大小来实现“编译时断言”的效果。在这种特殊情况下,这可能满足OP的需求,但在其他情况下,您确实需要基于类型大小的预处理器条件。这是如何做到的:

给自己写一点C程序,如:

/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* 'int' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }

编译。用您喜欢的脚本语言编写脚本,该脚本运行上述C程序并捕获其输出。使用该输出生成C头文件。例如,如果您使用的是Ruby,它可能看起来像:

sizeof_int = `./sizeof_int`
File.open('include/sizes.h','w') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER

然后将规则添加到Makefile或其他构建脚本中,这将使其运行上面的脚本来构建sizes.h

在需要根据大小使用预处理器条件的任何地方包含sizes.h

完成!

(您是否曾键入./configure && make来构建程序?configure脚本的作用基本上与上述类似......)

答案 6 :(得分:1)

作为此讨论的参考,我报告一些编译器获得sizeof()和预处理器时间。

JamesMcNellis回答是正确的,但有些编译器会遇到这种限制(这可能违反了严格的限制)。

作为一个例子,我指的是IAR C编译器(可能是专业微控制器/嵌入式编程的领先者)。

答案 7 :(得分:1)

#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))可能会有效

答案 8 :(得分:0)

在我的便携式c ++代码中(http://www.starmessagesoftware.com/cpcclibrary/)想要对我的一些结构或类的大小保护。

我找到了一个导致编译器抛出错误的解决方案,而不是找到预处理器抛出错误的方法(这不能用于这里所说的sizeof())。 http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99

我必须调整该代码以使其在我的编译器(xcode)中抛出错误:

static union
{
    char   int8_t_incorrect[sizeof(  int8_t) == 1 ? 1: -1];
    char  uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
    char  int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
    char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
    char  int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
    char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};

答案 9 :(得分:0)

在C11中添加了_Static_assert个关键字。它可以像:

一样使用
_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")

答案 10 :(得分:0)

尝试了上述宏后,此片段似乎产生了所需的结果(t.h):

#include <sys/cdefs.h>
#define STATIC_ASSERT(condition) typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(int) == 42);

运行cc -E t.h

# 1 "t.h"
...
# 2 "t.h" 2

typedef char _static_assert_3[ (sizeof(int) == 4) ? 1 : -1];
typedef char _static_assert_4[ (sizeof(int) == 42) ? 1 : -1];

运行cc -o t.o t.h

% cc -o t.o t.h
t.h:4:1: error: '_static_assert_4' declared as an array with a negative size
STATIC_ASSERT(sizeof(int) == 42);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.h:2:84: note: expanded from macro 'STATIC_ASSERT'
  ...typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
                                                       ^~~~~~~~~~~~~~~~~~~~
1 error generated.

42并不是所有问题的答案...

答案 11 :(得分:0)

为了在编译时根据其约束检查数据结构的大小,我使用了这个技巧。

.test{
width:0px;
}
.addTest{
   width:150px;
}

如果x的大小大于或等于限制MAX_SIZEOF_X,则gcc会抱怨“数组大小太大”错误。 VC ++将发出错误C2148(“数组的总大小不能超过0x7fffffff字节”)或C4266“无法分配常量大小为0的数组”。

这两个定义是必需的,因为gcc允许以这种方式定义零大小的数组(sizeof x-n)。

答案 12 :(得分:-8)

sizeof运算符不适用于预处理程序,但您可以将sizeof传递给编译器并在运行时检查条件:

#define elem_t double

#define compiler_size(x) sizeof(x)

elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
    printf("%d",(int)n);
} else {
    printf("%lf",(double)n);
}