![](/img/trans.png)
[英]How can the called (derived) function access the variables of the caller (base) function in c language?
[英]In C can a called function make the caller function return?
我想找到一种方法来使函数返回(具有特定值)调用它的函数。 在C中有可能吗? 也许通过检查调用堆栈?
抽象示例:假设我们有两个函数
int called() {
if (some_check_fails()) {
/* here make caller() return -1 so "Hello world!\n" is not printed */
}
}
int caller() {
called();
printf("Hello world!\n");
return 0;
}
我正在寻找放入/* ... */
部分的东西。
现实生活中的例子:我正在使用的代码是一个在SQLite文件中导出数据的函数。 这意味着每次都需要检查需要返回值的SQLite API的大量调用。 结果是一个看起来非常漂亮且功能太长的函数,其中if (resp_code != SQLITE_OK)
部分if (resp_code != SQLITE_OK)
重复:
sqlite3 *db;
char *err_msg;
/* Open the database in read-write mode, create it if not exists yet */
int resp_code = sqlite3_open_v2(filename, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
NULL);
if (resp_code != SQLITE_OK) {
fprintf(stderr, "SQLite error: cannot open database %s, %s\n", filename,
sqlite3_errmsg(db));
sqlite3_close(db);
return OMG_ERROR_HERE;
}
/* Create table */
char *query_table = "DROP TABLE IF EXISTS sometable; "
"CREATE TABLE sometable "
"(value int, data TEXT);";
resp_code = sqlite3_exec(db, query_table, 0, 0, &err_msg);
if (resp_code != SQLITE_OK) {
fprintf(stderr, "SQLite error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return OMG_ERROR_HERE;
}
/* Prepare statement */
char *query = "INSERT INTO sometable VALUES (@i, @s);";
sqlite3_stmt *stmt;
resp_code = sqlite3_prepare_v2(db, query, 150, &stmt, NULL);
if (resp_code != SQLITE_OK) {
fprintf(stderr, "SQLite error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return OMG_ERROR_HERE;
}
/* Start transaction */
resp_code = sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, &err_msg);
if (resp_code != SQLITE_OK) {
fprintf(stderr, "SQLite error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return OMG_ERROR_HERE;
}
/* AND SO ON */
我想要的是:
sqlite3 *db;
char *err_msg;
/* Open the database in read-write mode, create it if not exists yet */
int resp_code = sqlite3_open_v2(filename, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
NULL);
return_this_function_if_not_ok(resp_code);
/* Create table */
char *query_table = "DROP TABLE IF EXISTS sometable; "
"CREATE TABLE sometable "
"(value int, data TEXT);";
resp_code = sqlite3_exec(db, query_table, 0, 0, &err_msg);
return_this_function_if_not_ok(resp_code);
/* Prepare statement */
char *query = "INSERT INTO sometable VALUES (@i, @s);";
sqlite3_stmt *stmt;
resp_code = sqlite3_prepare_v2(db, query, 150, &stmt, NULL);
return_this_function_if_not_ok(resp_code);
/* Start transaction */
resp_code = sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, &err_msg);
return_this_function_if_not_ok(resp_code);
/* AND SO ON */
编辑 2015-12-21:我选择FUZxxl的答案是最好的,因为它是唯一一个实际回答我关于返回调用函数的问题。 另一方面, chux的答案 (基于Rowland Shaw和Ziffusion的 )正在以我喜欢的方式解决我的SQLite问题。
非常感谢各位!
这样的事情在C中是不可能的,但你可以接近。
标识符__func__
在每个函数的开头隐式声明为
static const char __func__[];
它的值是当前函数作为字符串的名称。 您可以编写一个类似函数的宏,隐式地将调用者的名称传递给被调用者。 如果应该接收调用者名称的函数是这样的:
void error_check_fun(const char *function, int code, int result);
你可以这样写一个宏:
#define error_check(code, result) error_check_fun(__func__, code, result);
类似地, __FILE__
和__LINE__
是分别扩展到当前源文件和行的宏。
你可以尝试这样的事情。
#define return_this_function_if_not_ok(db, sql_code, sql_msg, code) \
if ((sql_code) != SQLITE_OK) { \
fprintf(stderr, "SQLite error: %s\n", (*sql_msg)); \
sqlite3_free(sql_msg); \
sqlite3_close(db); \
return (code); \
}
sqlite3 *db;
char *err_msg;
/* Open the database in read-write mode, create it if not exists yet */
int resp_code = sqlite3_open_v2(filename, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
&err_msg);
return_this_function_if_not_ok(db, resp_code, err_msg, OMG_ERROR_HERE);
推荐像Rowland Shaw和@Ziffusion这样的东西
调用包含数据的函数并处理常见的内务管理。
int foo(char *err_msg, int code) {
if (msg) {
fprintf(stderr, "SQLite error: %s\n", err_msg);
sqlite3_free(err_msg);
} else {
fprintf(stderr, "SQLite error: %s\n", "Default error message");
}
sqlite3_close(db);
return code;
}
resp_code = sqlite3_exec(...);
if (resp_code != SQLITE_OK) return foo(err_msg, OMG_ERROR_HERE);
...
resp_code = sqlite3_prepare_v2(db, query, 150, &stmt, NULL);
if (resp_code != SQLITE_OK) return foo(NULL, OMG_ERROR_HERE);
建议进一步,包括文件和行号。 这是我发现非常有用的东西。
int bar(char *err_msg, int code, const char *file, int line) {
fprintf(stderr, "SQLite error:%s, Code:%d, File:%s, Line%d\n",
err_msg ? err_msg : "Default error message", code, file, line);
}
sqlite3_free(err_msg);
sqlite3_close(db);
return code;
}
#define foo(err_msg, code, file, line) bar((err_msg), (code), __FILE__, __LINE__)
您可以使用setjmp()/longjmp()
来获得此效果,但不完全像您想要的那样:
#include <setjmp.h>
#include <stdio.h>
int check_result;
int some_check_fails() {
return check_result;
}
int called(jmp_buf buf) {
if (some_check_fails()) {
longjmp(buf,1);
}
}
int caller() {
jmp_buf buf;
if (setjmp(buf)==0) {
called(buf);
printf("Hello world!\n");
return 0;
}
else {
printf("Failure\n");
return -1;
}
}
int main() {
check_result = 0;
caller();
check_result = 1;
caller();
}
输出:
Hello world! Failure
这种技术确实避免将检查放在多个位置,有效地实现了一种异常处理机制。 但是,还有其他方法可以清理代码而不需要使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.