Can someone please explain why I needed to add a second definition of a callback fct?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Can someone please explain why I needed to add a second definition of a callback fct?
I was writing some code for a sqlite3 application and wanted to use this code
PHP Code:
//***************************************************** // // Call-back function used by sqlite3_exec() // //***************************************************** static int process_sql( // Return 0 on success sqlite3 *db, // Data base being processed int argc, // Number of row values returned by query char **argv, // Data values returned char **azColName) // Name of the data columns returned { if (argc < 0) return 1; if (partition(argv[0], db)) { // If we get here we had a data base error. Abort. sqlite3_close(db); exit (1); } // Partition the root word if (partition(argv[0], db)) { // If we get here we had a data base error. Abort. sqlite3_close(db); exit (1); } return 0; }
Agreed, the first argument is typed as a void pointer to enable one to pass a pointer to anything into the call back function. But the "type mismatch" compile error specifically referred to the third argument.
Note that the compiler did not complain about
Code:
int (*callback)();
callback=process_sql;
rc = sqlite3_exec(db, select, callback, db, &errmsg);
which, I believe, shows that the "type" of process_sql is int *(void*,int,char**,char**), and my C language specification reference book (C a Reference Manual, Harbison and Steele, 1984) agrees.
Note also that the specification of the sqlite3_exec function:
Code:
int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
makes no mention of a sqlite3_callback type. Further, the definition of the sqlite3_callback
Code:
typedef int (*sqlite3_callback)(void*,int,char**, char**);
looks to me a match with
Code:
static int process_sql( // Return 0 on success
sqlite3 *db, // Data base being processed
int argc, // Number of row values returned by query
char **argv, // Data values returned
char **azColName) // Name of the data columns returned
except for the static qualification. (Which is there because I was looking at the code in the SQLite in 5 Minutes or Less on the SQLite web site, vis:
Code:
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
). I don't think that the static should cause the compiler to complain. Anyhow, I removed the static and still get:
Code:
comb4.c: In function ‘main’:
comb4.c:269: warning: passing argument 3 of ‘sqlite3_exec’ from incompatible pointer type
Hum. O.K., I think I've got it after looking at paulsm's reference. (Thanks Paul.)
The function declaration int foo() {...} tells the compiler to generate code to invoke foo when it sees a foo() somewhere in the code. But a pointer to foo has to be declared as int (*foo)() and so my use of an unqualified foo in the sqlite3_callback function was not correct.
The construct suggested by gramef works because it instructs the compile to use a pointer to the function.
Unfortunately that "explanation" seems to accurately convey my still confused state. Can anyone do it any more clearly?
The syntax *is* confusing - but this statement is absolutely correct:
Quote:
The function declaration int foo() {...} tells the compiler to generate code to invoke foo when it sees a foo() somewhere in the code. But a pointer to foo has to be declared as int (*foo)() and so my use of an unqualified foo in the sqlite3_callback function was not correct.
*Why* is the syntax so weird? Don't know. I imagine it basically has to do with the parenthesis operators (which are overloaded for "grouping" and "function call"), the "*" operator (which is overloaded for "multiplication", "pointer dereferencing" and "pointer declaration") and the relative precedence between these operators. But the basic answer is "it's just weird".
I notice that you are getting a warning not an error.
What happens if you declare process_sql to exactly match with sqlite3_callback (ie with void*) and then typecast within the function to a sqlite*?
is a better solution since it make the code much more legible.
But, at the point in the compilation where the warning is being generated the types of the arguments of the callback function are irrelevant since all that's being passes is a pointer to a function. Thus changing the type of the "pointer passed as the first argument to the callback function" in the callback function declaration has no effect on the warning message.
By the way, if you're interested in the complete program it's posted here. It's a app to take a string of characters from the standard input and write all possible permutations of all substrings of the input characters (of two characters or more), to the standard output. The OP in that thread was trying to debug an app that was intended to find all words that could be generated by rearranging the letters in an input word using a home-grown linked list program. I was trying to show the OP that reinventing the wheel was not always the best way to go. . .
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.