如何让程序崩溃然后在c

时间:2017-07-20 15:44:13

标签: c

我正在研究c中需要可变函数的东西,我需要根据每个参数的类型做一些事情。我知道通过here在执行过程中无法检查类型(我对他们试图在那里解决它的方式不感兴趣),所以我想知道是否存在任何类型的恐慌/恢复技术c,以便实现一种try / catch(我已经看过关于伪尝试捕获的this文章,但它们不允许运行不可执行的代码)。

我的想法是循环变量,并尝试不同的行为,只适用于特定类型。我知道这可能是不可能的。如果您知道任何事情,请提前致谢

编辑:如果你打算建议我只重构我的代码而不必这样做,那么让我解释一下:我正在尝试实现一个println()函数,类似于python和go中的那些函数,其中你可以简单地输入你想要打印的所有变量,而不必担心格式字符串(println(myvar,10,“nice”))。显而易见的答案就是不要这样做,因为格式字符串确实不那么难。但这听起来很有趣

4 个答案:

答案 0 :(得分:3)

传统上,可变函数的编写使得每个参数的类型可以通过先前参数的内容来预测。

您无法通过反复试验可靠地确定参数的类型。调用者将参数放在堆栈上,由函数决定堆栈上每个参数的偏移量和类型。

例如,如果你有可能有两个32位整数或一个64位整数..或一个有符号64位整数与一个无符号64位整数,你怎么知道它的区别?处理器很乐意将unsigned int视为signed int,并且如果你要求它计算错误的结果..没有错误告诉你你的类型错误。

在您编辑的问题中,我现在看到您要完成的任务。在python这样的高级语言中很容易做到这一点,其中所有参数都是可以在必要时进行内省以确定其类型的对象。 C不是那样的。您正在使用更低级别的数据.64位整数实际上是64位内存,包含整数值。您没有告诉您类型的元数据。您的代码必须知道它正在处理什么类型的数据以及它所在的位置。当参数在堆栈上传递时,你甚至无法知道传递了多少或者一个结束和下一个开始的地方,更不用说每个类型了。你的功能必须知道这一切。当你处理普通(非变量函数)函数时,这是编译器为你处理的东西,所以你不必考虑它。与python对比,其中参数位于高级列表或字典中,为您提供有关其所包含内容的大量信息。

答案 1 :(得分:2)

你正在谈论的是宣布这样的功能......

void println(...);

因为这是C编译器能够接受具有任意数量的未知类型参数的函数调用的唯一方法。但这不会编译,因为...必须以命名参数开头。

这个命名参数通常用于定义以下参数的格式,因为就编译代码而言,它只是内存中的一个字节加载。

答案 2 :(得分:1)

您提到的语言与之间存在根本区别。

例如使用一个解析器,它将从它的输入中确定每个变量的类型,即文本字符串。所以没有问题,因为你可以尝试多次转换,优先考虑不太可能的事情,直到你到达文本表示,因为可以打印的所有东西都可以表示为文本,这最终是{{1的目的功能。

例如,如果在编译时推断类型,那么这是可能的。但没有这样的功能,类型在编译之前表达,不能更改。在一个可变函数中,不可能知道每个参数的类型,函数应该有一个方法来确定这个或所有参数可以是相同的类型,例如text。

如果所有参数的类型相同,则可以编写一个接受以下语法的函数

print()

但在中执行此操作很简单,根本不可能,或者至少没有格式字符串和可变参数函数。

此外你试图尝试某些东西,如果它不起作用,尝试接下来的东西是行不通的,因为在中你可以将一个变量从多种类型转换为其他不兼容的类型而不会发生特殊情况,例如假设您像在示例中那样传递println("example text and a ", "10", " which is a number"); 10,然后尝试将"nice"提取为整数将起作用,您将最终打印"nice"的地址(或可能不是)而不是字符串"nice"

我说可能不是,因为c中的这种事情是未定义的行为,并且单独的代码无法真正预测到所产生的行为。

答案 3 :(得分:-1)

这是不可能的。不要再考虑它并寻找其他一些问题来解决:)

不仅无法从参数的二进制表示中分辨出参数的类型。除非你知道它的类型,否则你甚至不能告诉在哪里寻找参数

考虑一下这个有趣的未定义行为(我将格式字符串放入命名变量中以避免关于不匹配的格式转换的C警告):

#include <stdio.h>
const char* good="%d %f\n";
const char* bad="%f %d\n";
int main(void) {
    int a = 42;
    double b = 375.0;
    printf(good, a, b);
    printf(bad, a, b);  /* Undefined behaviour; format mismatch */
return 0;
}

输出(至少在一个流行的编译器上):

42 375.000000
375.000000 42

Live on ideeone

第二个printf就好像参数的顺序相反,所以它们实际上匹配了格式转换。怎么可能?

当然,未定义的行为可能会产生任何结果,因此观察到的行为很简单。但有一个解释:

在许多体系结构中,函数的前几个参数在特定的硬件寄存器中传递,而不是被压入堆栈。整数参数在某些通用寄存器中传递(按特定顺序),而浮点参数在浮点寄存器中传递。

所以(在第二种情况下)printf使用stdarg.h工具将参数1作为类型double而参数2作为类型int。碰巧,参数1是类型int,参数2是类型double,但运行时不知道,所以当调用va_arg(ap, double)来获取参数1时,{ {1}}在第一个浮点寄存器中查找参数(因为它将是列表中的第一个浮点参数)。当调用下一个va_arg来获取参数2时,它会在用于参数传递的第一个通用寄存器中查找该参数。