I have a question, well more of a verification.

In the program below, I'm packing a character array with some values. The first two are unsigned integers the next is a function pointer and the final is a string of characters...Now my question, is the casting correct for the function pointer? Just check the sections marked off with /*this section*/.

#include <stdio.h>
#include <string.h>

#define MAXLINE 4096

char *ca = "this is the string to pass";

void myhello(void)
{
	fputs("Hello, World!\n", stdout);
}

int main(int argc, char**argv)
{
	unsigned int i = 0;
	char recvline[MAXLINE];

	*(unsigned int*)&recvline[0] = 11111;
	*(unsigned int*)&recvline[sizeof(unsigned int)] = 22222;
 
	/*this section*/
	*(void(**)(void))&recvline[2 * sizeof(unsigned int)] = (void(*)(void))&myhello;
	/*this section*/

	for (i = 0; i < strlen(ca); ++i)
	{
		recvline[2 * sizeof(unsigned int) + sizeof(void*) + i] = ca[i];
	}

	fputs("\n\ndisplay packed character array\n\n", stdout);

	fprintf(stdout, "number one->%u\n", *(unsigned int*)&recvline[0]);
	fprintf(stdout, "number two->%u\n", *(unsigned int*)&recvline[sizeof(unsigned int)]);

	fputs("call function myhello->", stdout);
	/*this section*/
	(*(void(**)(void))&recvline[2 * sizeof(unsigned int)])();
	/*this section*/
	
	fprintf(stdout, "string->%s\n", &recvline[2 * sizeof(unsigned int) + sizeof(void*)]);
	return 0;
}

Edited 6 Years Ago by gerard4143: n/a

*(unsigned int*)&recvline[0] = 11111;

*(unsigned int*)&recvline[sizeof(unsigned int)] = 22222;
/*this section*/
*(void(**)(void))&recvline[2 * sizeof(unsigned int)] = (void(*)(void))&myhello;
/*this section*/

Casting is not for l-value. Only for r-value.

*(unsigned int*)&recvline[0] = 11111;

*(unsigned int*)&recvline[sizeof(unsigned int)] = 22222;
/*this section*/
*(void(**)(void))&recvline[2 * sizeof(unsigned int)] = (void(*)(void))&myhello;
/*this section*/

Casting is not for l-value. Only for r-value.

Correct, but not applicable. The result of cast, e.g. (int *) foo , is not an lvalue, and cannot be assigned. (int *) foo = bar; is incorrect. However, it can be indirected all right. * (int *) foo = baz; is perfectly OK.

Regarding the original post, though well-formed, the code may invoke an undefined behaviour. The alignment of unsigned int (and a function pointer) is stronger than that of a char; a situation specifically mentioned in 6.3.2.3.7 paragraph of a Standard.

Comments
success

Regarding the original post, though well-formed, the code may invoke an undefined behaviour. The alignment of unsigned int (and a function pointer) is stronger than that of a char; a situation specifically mentioned in 6.3.2.3.7 paragraph of a Standard.

Maybe I'm missing the boat on this one...Why would it matter where I store the function pointer. The value is just a pointer and when called it should call the appropriate code or is the possible 'undefined behaviour' an architectural issue.

The value is just a pointer

... so it must oblige to the pointer alignment requirements. If the pointer is fetched correctly, the call would succeed. However, if it is stored at the odd boundary, chances are you'd fetch not what you expect.

This UB stems from the architectural issues indeed. On most IA32 based platforms you wouldn't notice anything strange. Still it is an UB and must be avoided.

Comments
Thanks for the clear explanation

... so it must oblige to the pointer alignment requirements. If the pointer is fetched correctly, the call would succeed. However, if it is stored at the odd boundary, chances are you'd fetch not what you expect.

This UB stems from the architectural issues indeed. On most IA32 based platforms you wouldn't notice anything strange. Still it is an UB and must be avoided.

Thanks for clearing that up nezachem...

If memory serves, on a IA32 box non-aligned calls are inefficient but doable but like your posting advised, should be avoided....Thanks everyone for the input...

This question has already been answered. Start a new discussion instead.