On Mon, 13 Mar 2006, Horst von Brand wrote: >> > > This breaks down with variadic functions, which have no typing > > information. So doing this: > > execl("foo", "bar", my_struct_foo); > > doesn't give the compiler a chance to do the implicit cast and you get > > subtle breakage (in the same way that you would if you passed a long to > > a variadic function expecting a short). > > It just passes 3 "void *"'s, and casts back. What is so strange? It doesn't actually pass 3 "void *". Variadic functions pass their arguments as-is (apart from the normal integer promotion for small integer types: chars are passed as integers if "char" is smaller than "int"). So no actual casting takes place for the arguments, and execl("foo", "bar", my_struct_foo, NULL); passes in four pointers: two of type "char *", one of whatever my_struct_foo is ("struct foo *") and finally hopefully one of "void *" (modulo broken compilers). They might - in theory - have different sizes and representations. Now, the interesting effect of this is that simple things like printf("Pointer value %p\n", myfunction); is actually NOT STRICTLY PORTABLE CODE! Why? Because "%p" wants a void pointer, but "myfunction" is of a different pointer type, which may actually have a different size and a different representation entirely, so you can get total garbage printed out. So you have two choices: - be sane, and ignore insane architectures. In this case, the above is perfectly fine C code. - be insane, and care about it. In this case, you really do have to add the casts to be safe in theory. The "%p" for printf() is actually a wonderful example of why you really really really should ignore language lawyers. According to language lawyers, you should add that "(void *)" cast. But look around for how many such casts you can find in real code, and realize that the language lawyers just don't matter. A C compiler environment that requires it is simply broken, and sane people will refuse to use it for anything than small embedded work, because it's simply not usable. So while it's not true in theory, in _practice_ you should expect all pointers to be of the same size and use the same representation. Anything else is just too painful to be ever worth bothering with. (Remember near and far pointers from 16-bit DOS/Windows? Those environments at least had _explicit_ pointer sizes, making the problem less horrible, but that was clearly a disaster nonetheless. Pointers that implicitly have different sizes because they point to different types are even _worse_). Linus PS. Final words: while knowing that all pointer representations must be the same, and that NULL actually must be the bitwise binary "all zero" value (otherwise "memset(structptr, 0, structsize)" would break), it's equally important to know that the standard doesn't _guarantee_ it. Why? Because that way, when somebody tries to tell you that your code isn't standards conformant and might be unportable, you can say "yeah, I know, but only a total loser would ever care". Instead of incorrectly trying to argue that your code is "correct". - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html