繁体   English   中英

编译时断言以确定指针是否为数组

[英]Compile-time assertion to determine if pointer is an array

目前,我有以下代码块来进行安全字符串复制(它的工作原理):

#define STRCPY(dst, src) do { assert(((void*)(dst)) == ((void*) & (dst))); \
                              strlcpy(dst, src, sizeof(dst)); } while (0)

所以它接受如下构造:

const char *src = "hello";
char dest[5];
STRCPY(dest, src); //hell

并否认以下内容:

void (char *dst) {
    STRCPY(dst, "heaven"); //unknown size of dst
}

问题是代码块会产生一个断言。 有没有办法在编译时执行此检查?

所以我想在编译时遇到错误(比如创建一个负大小的数组 ),而不是在可能的情况下崩溃代码。

如果标准C可用,那么您可以这样做:

#define STRCPY(dst, src)                                        \
  _Generic(&(dst),                                              \
           char(*)[sizeof(dst)]: strlcpy(dst,src,sizeof(dst)) )

说明:

您不能在数组类型上使用_Generic表达式,因为它不是免于“数组衰减”规则的特殊情况之一(C176.3.2.1§3)。 因此,通过在我的示例中简单地使用_Generic((dst), ... ,当评估表达式时, dst将最终作为char* ,然后我们将丢失其原始类型的信息。

但是如果我们使用&获取数组的地址,我们会利用其中一种特殊情况并且不会发生数组衰减。 相反,我们最终得到一个数组指针,这意味着_Generic将必须检查预期类型和大小的数组指针: char(*)[sizeof(dst)]


作为侧面注意/安全问题,我从不使用do-while(0)宏并且不鼓励它们,但这是另一个故事。

我发现我的帖子已经关闭了一段时间,并按照提到的链接进行了操作 解决方案仅适用于GCC,但对我来说没问题,因为我也在GCC上进行夜间构建。 所以代码的预备稿是:

#if defined(__GNUC__)
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
#define STRCPY(dst,src) do{__must_be_array(dst);strlcpy(dst, src, sizeof(dst));}while(0)
#else
#define STRCPY(dst,src) do{strlcpy(dst, src, sizeof(dst));}while(0)
#endif

对于dst是否是数组的编译时断言,我会使用@Lundin解决方案(或_Static_assert )以防C11可用。

否则,我会使用以下内容:

#define BUILD_BUG_ON_NON_ARRAY_TYPE(e) (sizeof(struct { int:-!!(((void*)(e)) != ((void*) & (e))); }))

这基本上需要你的编译时计算表达式((void*)(dst)) == ((void*) & (dst))但不是在运行时使用assert只是以编译时断言的方式使用它。

所以,总的来说我会把你的宏改成:

#define STRCPY(dst, src) do { BUILD_BUG_ON_NON_ARRAY_TYPE(dst); \
                              strlcpy(dst, src, sizeof(dst)); } while (0)

如果你想检查它我能想到的唯一方法是:

assert((sizeof(dst)) != (sizeof(void*)));

但它只有在数组的大小与OPs系统上的指针大小不同时才有效

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM