I wrote this very small program that works fine until I remove the comments for the fprintf function.

Basically the program will prompt the user for a numeric value, when the user guesses right(1234) the program exits. When I remove the comments the program never exits...Does anyone have any idea why? I'm completely lost as to why it would behave like this...maybe its my compiler - gcc 4.4.1

#include <stdio.h>
#include <stdlib.h>

unsigned long testval = 1234;

void* foundit(void)
{
	fputs("found it!\n", stdout);
	return (void*)0;
}

void* tryit(void)
{
	unsigned long val;

	fputs("enter a value/guess->", stdout);
	fscanf(stdin, "%u", &val);
	
	if (val == testval)
	{
		return (void*)&foundit;
	}
	else
	{
		return (void*)&tryit;
	}
}

int main(int argc, char**argv)
{
	void *addr = (void*)&tryit;

	//fprintf(stdout, "ans->%u\n", 1);	//remove comments and program runs 
							//but fails to exit with correct value
	while ((addr = ((void*(*)(void))addr)()))
	{}
	exit(EXIT_SUCCESS);
}

Recommended Answers

All 16 Replies

>>while ((addr = ((void*(*)(void))addr)())

Didn't your compiler produce an error or warning on that line?? tryit() does not return a value, yet in the above addr is being assigned the return value of tryint(). You can't have it both ways. try this: while( addr() )

>>while ((addr = ((void*(*)(void))addr)())

Didn't your compiler produce an error or warning on that line?? tryit() does not return a value, yet in the above addr is being assigned the return value of tryint(). You can't have it both ways. try this: while( addr() )

No the complier had no problems casting a void pointer to a function..should it?
And for tryit() the if statement assures that the function returns a value..

But that isn't the problem...The problem is when I remove the comments from this line

//fprintf(stdout, "ans->%u\n", 1);

The program fails to exit correctly...Note the program works as intended while the comments are there...

Worked fine for me using vc++ 2008 express

ans->1
enter a value/guess->1234
found it!
Press any key to continue . . .

Worked fine for me using vc++ 2008 express

Humph...That means I'm going have to walk through some assembler and find out why removing the comments from this line

fprintf(stdout, "ans->%u\n", 1);

causes the program to behave differently...well besides printing 1 to the display..

Thanks for trying the program Ancient Dragon

>>well besides printing 1 to the display..

The reason for that should be obvious.

Also compiled with Code::Blocks using MinGW (gcc 3.4.5) and it worked ok.

Well I tried compiling the code on GCC 4.3.2 and it worked. I think GCC 4.4.1 may be in need of an update...Thanks again Ancient Dragon

So to recap:

the code will not work correctly on GCC 4.4.1
but it will work correctly on GCC 4.3.2, GCC 3.4.5 and vc++ 2008 express

>No the complier had no problems casting a void pointer to a function..should it?
It might. Technically void* and functions pointers are incompatible and converting between them is undefined behavior. I've seen compilers give both warnings and errors for such a conversion. The good news is that you can avoid this problem entirely by taking advantage of the fact that any function pointer type can be converted to any other function pointer type and back with well defined behavior (provided you call the function pointer with the correct type):

#include <stdio.h>
#include <stdlib.h>

unsigned long testval = 1234;

/*
Define a generic function pointer 
type for temporary conversion
*/
typedef void (*func_t)(void);

/*
Define a null value with the 
generic function pointer type
*/
void null_func(void) { }

func_t foundit(void)
{
  fputs("found it!\n", stdout);
  return null_function; /* No cast needed */
}

func_t tryit(void)
{
  unsigned long val;

  fputs("enter a value/guess->", stdout);

  /* Note the format specifier. %u was incorrect */
  fscanf(stdin, "%lu", &val);

  if (val == testval)
  {
    return (func_t)foundit; /* Safe cast */
  }
  else
  {
    return (func_t)tryit; /* Safe cast */
  }
}

int main()
{
  func_t addr = (func_t)tryit; /* Safe cast */

  fprintf(stdout, "ans->%u\n", 1U);

  while (addr != null_func) {
    /* Cast back to the correct type before calling */
    addr = ((func_t(*)(void))addr)();
  }

  /* A call to exit really isn't necessary from main */
  return 0;
}

>But that isn't the problem...
>The problem is when I remove the comments from this line

It might actually be. In my experience, when commenting out random unrelated lines suddenly causes a broken program to work, it's often a result of undefined behavior.

>the code will not work correctly on GCC 4.4.1
>but it will work correctly on GCC 4.3.2, GCC 3.4.5

File a bug report and see what comes of it then.

>No the complier had no problems casting a void pointer to a function..should it?
It might. Technically void* and functions pointers are incompatible and converting between them is undefined behavior.

Could you give an example....

>Could you give an example....
Your code is an example, my fix for your code is a counter-example. What more do you want? How about a quote from the standard:

1 A pointer to void may be converted to or from a pointer to any incomplete or object
type. A pointer to any incomplete or object type may be converted to a pointer to void
and back again; the result shall compare equal to the original pointer.

The key terms here are incomplete and object type. An object type is distinct from a function type, and incomplete types are defined as object types that lack size information.

I said "technically" in my original post because even the standard lists this as a common extension:

1 A pointer to an object or to void may be cast to a pointer to a function, allowing data to
be invoked as a function (6.5.4).
2 A pointer to a function may be cast to a pointer to an object or to void, allowing a
function to be inspected or modified (for example, by a debugger) (6.5.4).

Originally Posted by C99 Section 6.3.2.3

1 A pointer to void may be converted to or from a pointer to any incomplete or object
type. A pointer to any incomplete or object type may be converted to a pointer to void
and back again; the result shall compare equal to the original pointer.

Maybe I'm having problems with this statement
"the result shall compare equal to the original pointer"

Then again I never was a language lawyer

>Maybe I'm having problems with this statement
>"the result shall compare equal to the original pointer"

It means that you can convert an object pointer to or from a void pointer without any loss of data.

I don't really see your point....You go out of your way to note this issue and then your quotes verify that indeed it is a very common extension to the language....Is your point that is not 100% the standard? I can live with that, I'm very comfortable living in the common extensions of the language...

>I don't really see your point....
That much is obvious.

>Is your point that is not 100% the standard?
My point is that it could potentially be the cause of your problem because a compiler is not required to support it. Didn't I make that clear already? Technically it's undefined behavior and when commenting out random lines makes the code work, undefined behavior is the most likely culprit.

>I can live with that
I won't hold that against you. Personally, I prefer the option that's guaranteed to work in all cases rather than the option that will only work on the version of the compiler that I'm currently using.

I wrote this very small program that works fine until I remove the comments for the fprintf function.

Basically the program will prompt the user for a numeric value, when the user guesses right(1234) the program exits. When I remove the comments the program never exits...Does anyone have any idea why? I'm completely lost as to why it would behave like this...maybe its my compiler - gcc 4.4.1

#include <stdio.h>
#include <stdlib.h>

unsigned long testval = 1234;

void* foundit(void)
{
	fputs("found it!\n", stdout);
	return (void*)0;
}

void* tryit(void)
{
	unsigned long val;

	fputs("enter a value/guess->", stdout);
	fscanf(stdin, "%u", &val);
	
	if (val == testval)
	{
		return (void*)&foundit;
	}
	else
	{
		return (void*)&tryit;
	}
}

int main(int argc, char**argv)
{
	void *addr = (void*)&tryit;

	//fprintf(stdout, "ans->%u\n", 1);	//remove comments and program runs 
							//but fails to exit with correct value
	while ((addr = ((void*(*)(void))addr)()))
	{}
	exit(EXIT_SUCCESS);
}

Found the problem...well it'll compile and run as intended with this change. It was this line.

fscanf(stdin, "%u", &val);

When I changed it to it ran as intended

fscanf(stdin, "%lu", &val);

I'm still not 100% sure why this is happening...maybe its the common extensions I choose to associate with....

"%u" is for unsigned in, "%lu" is unsigned long int, two different int sizes.

"%u" is for unsigned in, "%lu" is unsigned long int, two different int sizes.

Yeah I know the last line was a pun

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.