I need to print the name of functions which is already stored in a function pointer.
Eg.
preValidateScriptHookFunc = (srvScrGenFuncPtrType)SRV_VerifyPymtOrderMaintDtls_validate_data;
I want the value "SRV_VerifyPymtOrderMaintDtls_validate_data" as output during program run via preValidateScriptHookFunc.
preValidateScriptHookFunc is a function pointer which can store any function name.
Please let me know which format specifier should be used in printf or fprintf.
This is generally not possible - see http://c-faq.com/misc/symtab.html.
I'm afraid that without using debug info api (which depends on the platform your in) or using some kind clever trickery with register the pointer in a lookup table it is just not possible.
Depending on your compiler, you might be able to use a pre-defined macro.
http://msdn.microsoft.com/en-us/library/b0084kay(VS.71).aspx
As Ofir says in his answer, you basically cannot do that. The names of the functions only exist before linking is done (they may endure afterwards in debugging data). After link it's only pointers.
If you're willing to store the function addresses somewhere and compare to them, you can do somewhat like this:
$ cat 3922500.c
#include <stdio.h>
char *fxname(void *fx) {
if (fx == fprintf) return "fprintf";
if (fx == gets) return "gets";
if (fx == scanf) return "scanf";
return "(unknown)";
}
int main(void) {
void (*fx)(void);
fx = gets; printf("name: %s\n", fxname(fx));
fx = putchar; printf("name: %s\n", fxname(fx));
return 0;
}
$ gcc 3922500.c
3922500.c: In function 'main':
3922500.c:12: warning: assignment from incompatible pointer type
3922500.c:13: warning: assignment from incompatible pointer type
/tmp/ccvg8QvD.o: In function `fxname':
3922500.c:(.text+0x1d): warning: the `gets' function is dangerous and should not be used.
$ ./a.out
name: gets
name: (unknown)
Related
I was randomly experimenting with code and tried to assign printf to an integer variable, using different compilers. Different values were returned. What is the explanation for that?
#include <stdio.h>
int main ()
{
int x;
x = printf;
printf ("%d", x);
return 0;
}
Value returned on my compiler is 4195360.
Look at the warnings from your compiler. (If your compiler doesn't show a warning for this code, look up how to configure it to show useful warnings.)
a.c:5:5: warning: incompatible pointer to integer conversion assigning to 'int'
from 'int (const char *, ...)' [-Wint-conversion]
x = printf;
^ ~~~~~~
1 warning generated.
printf is a function. Every function can be used as a pointer to that function. A pointer to a function is a way to refer to the function that can be placed into a variable. Typically, it's the address of the code of the function in memory.
It's possible to assign a pointer to an integer. The resulting value depends on your system. The integer is typically the address of the code of the function in memory.
There's nothing useful you can do with this value except in some very particular circumstances (such as crafting binary exploits, or managing dynamic code loading). Anything you can do with the value would be very specific to a particular hardware and software environment.
I'm trying to call a function (on line 15) just via a cast but only the first argument is getting passed, how could I fix it?
I tried to change the float value "2" to 2.0f to declare it's a float and not an int but it's still not working.
!Note that the code is horrible because it's a code golf, the line 15 has to be in a dll form later, this code here is just a test program to avoid launching the target process multiples times. Here's my actual code with a score of 58 chars
DllMain(a,b,c){((int(*)(int,float))927309216)(7903472,2);}
#include <Windows.h>
#include <stdio.h>
char * sSkelModelStencil = "SkelModelStencil"; //here I reproduce the char like it is in the memory
void SetConsoleFloat(const char *sKey, float fVal) //this is the reproduction of SetConsoleFloat in CShell.dll
{
printf("arg1: %s arg2: %f\n", sKey, fVal); //printing the arguments getting passed into the function
return;
}
int main()
{
while (1) {
SetConsoleFloat("SkelModelStencil", 2); //calling the reproduction function
((int(*)())SetConsoleFloat)(sSkelModelStencil,2); //calling the reproduction function via a cast & using SetConsoleFloat addr
system("PAUSE");
}
}
In some architectures, the way arguments are passed depends on the way they're declared. For instance, special registers may be used for float parameters. It's the declaration of the function type that matters, not the declaration of the argument expression.
The parameter signature () is different from (const char *sKey, float fVal), and as a result the fVal argument is being passed differently from the way the function expects to receive it.
First of all - this is atrocious code, don't do that.
Secondly - compile your code with compiler warnings on, so the compiler can tell you where you might be going wrong. Of course, you need a proper C compiler (which MSVC is not, in case you were using that). gcc will tell you:
a.c:15:10: warning: function called through a non-compatible type
But, to answer your question: You're casting into the wrong type of function: You're using the function type void (); but you need void (const char*, float). So, try:
((void(*)(const char*, float))SetConsoleFloat)(sSkelModelStencil,2);
instead of your existing line 15. It's also a good idea to separate casts from type definitions of functions - for clarity - so you would have:
typedef void (*scf_function_t)(const char*, float);
earlier, and then:
((scf_function_t) SetConsoleFloat)(sSkelModelStencil,2);
but again - there's really no good reason to do any of this in the first place.
I'm writing a program for converting temperatures and I have most of it written. When I compile and run the program, it doesn't do the calculations, doesn't seem to recognise the C/F choice and it isn't working out the reset part either.
What am I doing wrong?
#include <stdio.h>
#include <ctype.h>
float promptTemp(float kelvin)
{
printf("Please enter a sample temperature in degrees Kelvin:\n");
float convertFahrenheit(float temp)
{
}while(reset == 'y');
return(0);
}
The problem in your code is
promptTemp(temp);
and
promptConvert(convert);
you're neither
passing the pointer to variables as argument
collecting the return value.
So,
if(convert == 'c')
is esseentially using (reading) an uinitialized variable convert which in turn invokes undefined behaviour.
Please be aware that the values of the variables from your main function are changing inside your functions, because you are only passing a copy, and only that copy is modified inside the function and then lost. ( even though they have the same name ).
Try to pass the parameters as references or pointers.
You are not storing the return value of the function in the main function:
promptTemp(temp);/promptConvert(convert);
try result = promptTemp(temp);
and also you are not passing anything to the
promptTemp() function
There are a few things that need to be modified:
promptConvert(convert);
It isn't doing anything to convert variable. If you want the value returned from the function to be stored in the function, do this:
convert = promptConvert(convert);
If you want the function to modify the value of variable passed to it, do this:
char promptConvert(char &convert) //pass by reference
Similarly for other functions, like:
temp = convertCelsius(temp);
or
float convertCelsius(float &temp)
There are other functions which need the same modification too, like float convertFahrenheit(float temp)
By using a decent compiler, all the problems in this code will be revealed. One example of such a compiler is GCC. Get that one and then use it properly:
gcc -std=c11 -pedantic-errors -Wall -Wextra
Compiler output:
C:\tmp>gcc test.c -std=c11 -pedantic-errors -Wall -Wextra
test.c: In function 'promptConvert':
test.c:17:5: warning: statement with no effect [-Wunused-value]
tolower(convert);
^
test.c: In function 'promptReset':
test.c:72:5: warning: statement with no effect [-Wunused-value]
tolower(reset);
^
test.c: In function 'main':
test.c:87:9: warning: 'temp' is used uninitialized in this function [-Wuninitial
ized]
promptTemp(temp);
^
test.c:89:9: warning: 'convert' is used uninitialized in this function [-Wuninit
ialized]
promptConvert(convert);
^
test.c:100:9: warning: 'reset' is used uninitialized in this function [-Wuniniti
alized]
promptReset(reset);
^
So in addition to the bugs already pointed out in other answers, you also don't store the return value of tolower(). Should have been convert = tolower(convert);
I have something along the lines of:
#include <stdio.h>
typedef struct {
char s[100];
} literal;
literal foo()
{
return (literal) {"foo"};
}
int main(int argc, char **argv) {
printf("%s", foo().s);
return 0;
}
And I get this error when compiling it (with gcc):
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘char[100]’ [-Wformat=]
any1 has any ideas on how I can fix it? And what is wrong with that function return type?
EDIT
The problem (if not clear in the discussion) was the c standard gcc was using to compile the file. if you use -std=c99 or -std=c11 it works.
It is not an error but a warning, not all warnings that -Wall produces are sensible.
Here the compiler is "kind-of" right: before evaluation your argument is an array and not a pointer, and taking the address of a temporary object is a bit dangerous. I managed to get rid of the warning by using the pointer explicitly
printf("%s\n", &foo().s[0]);
Also you should notice that you are using a rare animal, namely an object of temporary lifetime, the return value or your function. Only since C99, there is a special rule that allows to take the address of such a beast, but this is a corner case of the C language, and you would probably be better off by using some simpler construct. The lifetime of the pointer ends with the end of the expression. So if you would try to assign the pointer to a variable, say, and use it later on in another expression, you would have undefined behavior.
Edit(s): As remarked by mafso in a comment, with C versions from before C99, it was not allowed to take the address of the return value of the function. As Pascal Cuoq notes, the behavior of your code is undefined even for C99, because between the evaluation of the arguments and the actual call of the function there is a sequence point. C11 rectified this by indroducing the object of temporary lifetime that I mentioned above.
I don't exactly why maybe someone with more knowledge in C than me can explain it but writing main() on this way:
int main(int argc, char **argv) {
literal b = foo();
printf("%s", b.s);
return 0;
}
The code prints "foo" correctly on GCC 4.5.4
I am very new to C Programming and have a doubt... I've been asked to find errors in certain segments of C code... and this segment has me a bit confused so would appreciate the help...
int main(void)
{
int myInt = 5;
printf("myInt = %d");
return 0;
}
As far as i understand there is nothing wrong in this code. What i wanna know is why is this statement printing out a random number ??
The output i get is
myInt = 1252057154
Would appreciate the help... Thanks
You should read more about C programming.
And you should enable all warnings and debugging when compiling. With GCC, this means gcc -Wall -Wextra -g (on Linux at least).
When compiling with
gcc -Wall -Wextra -g john.c -o john
I am getting the following warnings:
john.c: In function ‘main’:
john.c:4:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
john.c:4:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
john.c:4:5: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat]
john.c:3:9: warning: unused variable ‘myInt’ [-Wunused-variable]
So the correction is simple:
/* file john.c */
#include <stdio.h>
int main(void)
{
int myInt = 5;
printf("myInt = %d\n", myInt);
return 0;
}
which gets compiled without warnings.
Notice the \n at the end of printf format string. It is important.
Always enable all the warnings the compiler can give you and trust the compiler, so correct your code till no warnings is given.
And learn to use the debugger (e.g. gdb on Linux).
The behavior you observed is undefined behavior; anything could happen with a standard conforming implementation of C (even an explosion).
Happy hacking.
printf (and similarly scanf) works like this:
Let's say you issue a call to printf
printf("%d some text %f %u %hu some more text\n", arg1, arg2, arg3, arg4)
printf goes over the format string and replaces %? with an argument, based on ?
%d some text %f %u %hu some more text
| | | |
arg1 arg2 | arg4
arg3
Now the thing with functions taking variable number of arguments is that, they don't know if the arguments exist, that's why they just take data from a specific part of the stack based on the format string. If you write:
printf("%d %f %u\n");
it reads three non existing data from the stack, most probably get the values stored when calling the function (values that should be hidden from you)
Well, if it's printing something wrong, the problem is in the printf call:
printf("myInt = %d");
Which arguments you're expected to pass?
It should be this:
printf("myInt = %d",myInt);
If you don't include the variable, then it basically pulls a random chunk of memory in. In addition, it might cause more wierd stuff to happen if you do this with a larger chunk of code. Always make sure that you have as many variables from a printf statement as you need, or bad stuff will result.
printf is a function that receives one or more arguments.
In your case it received only one argument (which is legal) but the argument containes %d which tells printf to take the second argument instead of the %d.
printf takes the "second argument" from the stack, and because only one argument was pushed to the stack (the string), it uses the return address as the second argument.
int main(void)
{
int myInt = 5;
printf("myInt = %d",myInt);
return 0;
}
The only change in the code is I added myInt variable in the printf statement if you see at the end.Whenever a variable is assigned some value it can be displayed only by passing it to the printf() function with the corresponding type specifier.Its a rule in C.