限制要创建的数据结构的大小

时间:2019-04-20 12:26:06

标签: c macros

我的头文件是

typedef struct vector vector;

vector * vector_create(size_t size);

c文件:

vector * vector_create(size_t size){
    if(size >= PTRDIFF_MAX)
        return NULL;
    //actual creation logic
}

我需要将vector的大小限制为不超过PTRDIFF_MAX,因为我需要从另一个向量中减去指向一个向量元素的指针。问题出在我要测试时

void test_create_vector_too_large(void){
#if SIZE_MAX >= PTRDIFF_MAX + 1
    list * lst = list_create(((size_t) PTRDIFF_MAX) + 1);
    assert(!lst);
#endif
}

此代码会产生大量警告

/home/kjroff/main.c:55:32: warning: integer overflow in preprocessor expression
 #if SIZE_MAX >= PTRDIFF_MAX + 1
                                ^
/home/kjroff/main.c:55:29: warning: the right operand of ">=" changes sign when promoted
 #if SIZE_MAX >= PTRDIFF_MAX + 1

#if宏的目的是检查ptrdiff_t的上限是否超过size_t的上限。如果它们相同,则此测试没有意义。但这是在PTRDIFF_MAX < SIZE_MAX情况下发生的。

如何正确编写这样的断言?

2 个答案:

答案 0 :(得分:4)

该比较通常是无用的,因为size_tptrdiff_t的宽度通常相同,但是size_t是无符号的,而ptrdiff_t是有符号的,所以SIZE_MAX是必须大于PTRDIFF_MAX。这不是C标准严格指定的,因为size_t只是用于大小表达式的类型,尽管有意图,但并未明确指定它足以表示任何对象的大小。同样,ptrdiff_t只是用于指针差异的类型,尽管有意图,但并未明确指定它足以代表所有指针的差异。

也就是说,您可以将比较更改为SIZE_MAX > PTRDIFF_MAX,这与pmg所指出的等效。使警告安静的另一种方法是将1更改为1u,产生SIZE_MAX > PTRDIFF_MAX + 1u。根据C 2018 6.10.1 4,在预处理中,整数类型的行为类似于intmax_tuintmax_t,因此1u的类型为uintmax_t,因此{{1 }}将转换为PTRDIFF_MAX,然后添加到uintmax_t(不会溢出),并且比较将在两种1u类型之间进行(避免警告)。

问题指出:“我需要将向量的大小限制为不超过PTRDIFF_MAX,因为我需要从另一个向量中减去指向一个向量元素的指针。”但是uintmax_t的单位是一个字节,而size_t的单位是一个数组元素。除非ptrdiff_t类型为单个字节,否则将减去两个vector指针的结果。即使在vector *难以覆盖所有可能大小的受约束系统中,size_t也应舒适地为两个ptrdiff_t指针的差异留出空间,而不管底层数组的大小如何。因此测试vector *似乎没有用。

答案 1 :(得分:2)

  

如何正确编写这样的断言?

代替

#if SIZE_MAX >= PTRDIFF_MAX + 1

减去(SIZE_MAX至少为65535),所以不可能溢出。

#if SIZE_MAX - 1 >= PTRDIFF_MAX

或仅使用> @pmg

#if SIZE_MAX > PTRDIFF_MAX