确定具有正确返回类型的原型的存在 [英] Determining presence of prototype with correct return type

查看:59
本文介绍了确定具有正确返回类型的原型的存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我刚想出的 C 黑魔法中的一个随机问题:

Here's a random problem in C black magic I just came up with:

编写一个函数,如果 malloc 已被原型化为返回指针类型,则返回 1,如果 malloc 的返回类型为 int,则返回 0(隐式的或由于错误的原型),不调用任何实现定义或未定义的行为.

Write a function that returns 1 if malloc has been prototyped to return a pointer type and 0 if malloc has a return type of int (either implicitly or due to wrong prototype), without invoking any implementation-defined or undefined behavior.

我相信它是可以解决的,但我还没有找到解决方案.请注意,调用函数不是必需的,实际上是不可能的,因为调用具有不正确原型的函数是未定义的行为.我对配料有一些想法,但我认为如果我暂时不考虑它们,它会成为一个更好的谜题(可能还有更多不同的想法).

I believe it's solvable, but I haven't worked out the solution. Note that calling the function cannot be necessary and in fact is not possible since calling a function with the incorrect prototype is undefined behavior. I have some ideas for ingredients but I think it makes for a better puzzle (and possibly more diverse ideas) if I leave them out for now.

我不需要立即使用的解决方案,但它在 configure 脚本等中可能很方便.

I don't need the solution for any immediate use, but it could be handy in configure scripts and such.

更新:一个更好的例子(使用 strdup 而不是 malloc):

Update: A better example of the usefulness (with strdup instead of malloc):

#undef strdup
#define strdup(x) (strdup_has_proto ? strdup((x)) : my_strdup((x)))

即能够在源代码级别将 X_has_proto 实现为表达式可能是一种使用系统可能具有或不具有的功能的可移植方式,并回退到本地替换,而无需任何单独的 配置步骤.

i.e. being able to implement X_has_proto as an expression at the source level could be a portable way to use functions which a system might or might not have, and fall back on a local replacement, without needing any separate configure step.

推荐答案

部分答案及相关问题的解答:

Some partial answers and answers to related questions:

如果有问题的函数应该返回浮点类型,则测试很简单:

If the function in question is supposed to return a floating point type, the test is easy:

#define HAS_PROTO_FP_RET_1_ARG(f) !!((1?1:(f)(0))/2)

当且仅当 f 声明为返回浮点类型时,1 被提升为浮点类型,并且当且仅当 1 具有浮点数时,除以 2 会产生非零值类型.

The 1 gets promoted to a floating point type if and only if f is declared to return a floating point type, and division by 2 results in a nonzero value if and only if 1 has floating point type.

此测试对于检查 C99 数学函数是否存在很有用.

This test could be useful for checking for the presence of C99 math functions.

对于指针,表达式 (1?0:(f)(0)) 可能很有用 - 它的计算结果为 0(int) 或 (void *)0) (空指针常量)取决于 f 的返回类型.但是我还没有找到任何狡猾的方法来测试一个表达式是整数类型还是指针类型.

With pointers, the expression (1?0:(f)(0)) is potentially useful - it evaluates to either 0 (an int) or (void *)0) (a null pointer constant) depending on the return type of f. But I have yet to find any devious way to test whether an expression has integer or pointer type.

我遇到的大问题是 void * 不能参与指针算术并且不会在算术上下文中隐式转换为其他指针类型.例如,如果确实如此,这将起作用(也稍微违反了我关于 UB/IDB 的规则):

The big problem I'm running into is that void * cannot participate in pointer arithmetic and does not implicitly convert to other pointer types in arithmetic contexts. For example, if it did, this would work (slightly breaking my rules about UB/IDB too):

#define HAS_PROTO_PTR_RET_1_ARG(f) ((int)((char (*)[2])2 - (1?0:(f)(0))) == 1)

有什么办法可以解决这个问题吗?

Any ideas for getting around this problem?

更新:我有一个解决方案,它只依赖于 intmax_tint 大:

Update: I have a solution that depends on nothing more than intmax_t being larger than int:

#define HAS_PROTO_PTR_RET_1_ARG(f) ( \
    sizeof(int)!=sizeof(void *) ? sizeof ((f)(0)) == sizeof(void *) : \
    sizeof (1?(intmax_t)0:(f)(0)) == sizeof(void *) )

有两种情况.如果 intvoid * 的大小不同,我们只需检查返回值的大小.否则,intvoid * 的大小相同,因此(根据大假设)intmax_tvoid *大小不一样.如果返回类型为int,我们构造一个类型为intmax_t的表达式,如果返回类型为void *<,则构造一个类型为void */code>,并测试其大小.

There are two cases. If int and void * have different sizes, we simply check the size of the return value. Otherwise, int and void * are the same size, so (by the big assumption) intmax_t and void * are not the same size. We construct an expression whose type is intmax_t if the return type is int, and void * if the return type is void *, and test its size.

此宏仅在 intintmax_tvoid * 都具有相同大小的机器上失败.实际上,这意味着仅在具有 64 位或更大 int 的 DSP 上.由于几乎所有真正的 POSIX 和类 POSIX 系统都具有固定大小的 32 位 int 并且 intmax_t 要求至少为 64 位,因此它的便携性足以让我感到高兴.

This macro fails only on machines where int, intmax_t, and void * all have the same size. Practically speaking, that means only on DSPs with 64-bit or larger int. Since pretty much all real POSIX and POSIX-like systems have fixed-size 32-bit int and intmax_t is required to be at least 64-bit, this is portable enough to make me happy.

这篇关于确定具有正确返回类型的原型的存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆