Click here to Skip to main content
15,884,628 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello export expert,
Below is the code I found
C++
#include <iostream>
#include <cstdlib>
#include <stdio.h>

using namespace std;

void a()
{
	printf("Hello World!\n");
}

int main()
{
	typedef int (*fun)();
	fun tmp = (fun)a;
	printf("0x%x\t0x%x\n",tmp,&a);
	if(tmp())
	{
		printf("a is ok!\n");
	}
	else
	{
		printf("a is not ok!\n");
	}
	system("pause");
}


But the result given is:
0x401318 0x401318
Hello world
a is not ok!

My compiler is CodeBlock GCC.
Please help me to explain this. What if I want it to print a is Ok.
Posted
Updated 19-Dec-12 15:21pm
v2
Comments
[no name] 19-Dec-12 21:44pm    
Hi, I know it is unsafe and I will not do this in my development. But I just came across this interesting thing and wish to figure out why and how. That is why I post this.
Mohibur Rashid 19-Dec-12 21:48pm    
You got a is not ok! is surprising. it is not suppose to do that, because if statement is suppose to get 18

Explanation of the code
C++
#include <iostream>
#include <cstdlib>
#include <stdio.h>

using namespace std;
 
void a()
{
	printf("Hello World!\n");
}
 
int main()
{
        // I am guessing the problem area starts here
	typedef int (*fun)();// declaring a type, when you would use the type it would represent a function pointer return integer
         defining a variable that would point to a function whose return type would be int and wont take any argument.
	fun tmp = (fun)a;   //here you have assigned the function but the mistake you have made is function a is void returning function. but you have done the type casting so no error is being showed. 
	printf("0x%x\t0x%x\n",tmp,&a);  //format string %x tells the compiler to print number in hexadecimal format. so, you have printed two hexadecimal data. temp is already returning a pointer(all pointer are 32 bit long). a is the function but when you type &a it means the address location of function a()
	if(tmp()) // this will act bit wrong. if you call a() instead temp() you will get compilation error. but you are using pointer of a() which has wrong type casting. anyway because of nothing returned you are not getting this. But there would be situation where this condition will be true. 
	{
		printf("a is ok!\n");
	}
	else
	{
		printf("a is not ok!\n");
	}
	system("pause");
}


I am not sure if any of this will go through you. Another advice learn carefully. You have made a mistake which is considered as dangerous side of c/c++.

change your function a type from void to int


explanation of how return work: (Some of my statement might be wrong. Let me know if I am)

When a function return a value compiler save the return value in AX register first then make the next move.
i.e.
C++
int a()
{
 return 10; // 
}

int main()
{
 int b=a(); // this line will be break up into many many small pieces of assembly 
 //but in simple
 //10 will be stored in ax resister. then the value will be stored in b variable.
}


now, printf function return the number of character it printed. the value is automatically stored in ax register. In your void function that you have developped will not return anything but ax register will have value 13. so, your if statement will be true but not false.

Another example of function return behave:

C++
#include <stdio.h>

using namespace std;
 
int a()
{
	if(0)
		return 1;  //compiler wont reach here
	printf("Hello World!\n");
 //function end without returning. compiler would create a simple warning.
}
 
int main()
{
	printf("%d\n",a()); //can you guess what it would print?
}


the answer is the printf function in the main function would print 13. because printf function in in a() function prints 13 character. so it return 13. which remain in AX register. which is printed by printf function in the main function

Why?
 
Share this answer
 
v5
Comments
chaau 19-Dec-12 21:36pm    
be careful here. Someone downvotes the proper answers
Mohibur Rashid 19-Dec-12 21:43pm    
I can see that
[no name] 19-Dec-12 21:44pm    
Hi, I know it is unsafe and I will not do this in my development. But I just came across this interesting thing and wish to figure out why and how. That is why I post this.
Mohibur Rashid 19-Dec-12 22:01pm    
check my updated answer
[no name] 19-Dec-12 22:11pm    
OK, I got you. It seems that my compiler got wrong in somewhere. Yes, I know it is very dangerous and I will not write it into my development. Thank you.
Gived that the code is undefined, it is pointless to explain it.

It is illegal to cast a function pointer to another type and use it as it. The result is not defined and thus not portable. In practice, the result will be specific to a compiler and might even vary according to options.

Undefined simply means that the result is not defined and can be anything. It will depends on how the compiler is implemented and it might even cause crashes in some cases as there are many calling conventions some of which the caller adjust the stack and other the callee.

Typically since a register is used for small type return value, the result after a cast would be whatever is remainding in the register that is usually used for function returning an int.

Since a void function returns notthing, it generally does nothing on the value stored in the register and after a cast, the result will be whatever was already in that register (might be last result of previous function call).

If you really want to understand what is happening under the hoop, then look at the disassembly code window.
 
Share this answer
 
v2
Comments
Mohibur Rashid 19-Dec-12 23:48pm    
even though I argued, but I agree
you need to change the function a like this:

C++
int a()
{
	printf("Hello World!\n");
	return 1;
}


Just let me know if you need an explanation
 
Share this answer
 
v2
Comments
Christian Graus 19-Dec-12 21:21pm    
The question is, why does it fail ? It resolves to true when I run it here.
chaau 19-Dec-12 21:26pm    
he is trying to cast void a() to int (*fun)(). So, different compilers treat void differently. MS thinks that void is true, GCC thinks that void is false.

Anyway, this is an unsafe casting, and needs to be fixed, as I suggested in my solution
[no name] 19-Dec-12 21:28pm    
Thanks. I konw that if I change a() with a return value like int here but then I run,it still shows that a is NOT OK. I guess It is not about the return value, what matters is the address of the a() function.
chaau 19-Dec-12 21:34pm    
If you want to check the address of the function pointer, you need to change if(tmp()) to if(tmp). Otherwise, you are calling function "a" via the pointer tmp. Function a returns void. void gets converted to 0 in your compiler. BTW, who is that person who downvoted my answer? Please explain the reason for this.
Try.

C++
int a()
{
printf("\nHello World\n");
return 1; //or 0 your call
}


Your program should work. And remember when working with function pointers:
typedef int (*foo) ();
returntype typename parameters


so for your original function void a(); it should have been
typedef void (*foo)();
foo fnptr=&a; //& not required

but since you are checking for a value inside if statement while calling the function. You probably wanted a function that returned some value.
Since your original function is void the if condition will always be false and the else part will be executed.

A better way to go about this would be:
C++
int a(int param)
{
  printf("Hello World\n");
  return param;
}

int main()
{
  typedef int (*Fun_Ptr)(int);
  Fun_Ptr funPtr=&a;
  
  int aNumber;
  printf("\nEnter a number :");
  scanf("%d",&aNumber);
  if(50>funPtr(aNumber))
     printf("\nOMG!!This is working");
  else
     printf("\nThis was supposed to work");
}

Its really simple eg and we are doing something useless such as pass a parameter to the function and returning it back unchanged. You could perform some sort of opertion on it like modulo or some thing. Anyway the idea is to understand the syntax for declaring a function pointer properly and using it properly.
Though the compiler will allow you to run your code its not safe and this kind of behaviour in the code should be avoided to all best intents.

I hope this is Clear.
 
Share this answer
 
Though I'm not entirely sure (I don't know the internal details of these compilers), I have a theory why this might happen:
GCC may see it as false because it may be in GCC that the caller allocates space on the stack for the return value of the function, so it would push 0 to make a space, and that value is never actually set because the function you called is really a void, but the code thinks that 0 that was pushed to make space is the return value.

The fact that it works in the MS compiler (as reported by other members) could be a result of allocating memory for functions differently, the MS compiler may have the callee allocate it's own stack space for return values, but since it doesn't return anything that memory was used for something else (like a character in the string) and when it returns the caller the caller thinks that was meant as a return value.
 
Share this answer
 
This calls the a method via a function pointer. a is returning 0, the check is relying on 0 meaning false. Your compiler is broken. The Microsoft compiler gives the expected result. It's also free, there's free editions you can download.
 
Share this answer
 
Comments
chaau 19-Dec-12 21:29pm    
can you tell me why you believe that "a returning 0". What made you assume this?
Christian Graus 19-Dec-12 21:45pm    
doesn't 0 equate to false ? I meant it resolves to 0, it's not returning anything, clearly
chaau 19-Dec-12 21:49pm    
why do you think it resolves to 0. I do not remember seeing it anywhere in C or C++ documentation
Christian Graus 19-Dec-12 21:51pm    
I admit I've not done C++ for a while but if it does not resolve to 0, why does the check fail ? Doesn't if (x) come back false if a pointer is null ( i.e. 0 ) ?
chaau 19-Dec-12 22:00pm    
Please, please, please check the if statement again. Can you see extra brackets there? if(tmp()). This is not a test for a valid pointer, this is a call of the function "a", with the return value of which has been casted to int. If he needed to test that the pointer valid he would have to use if(tmp)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900