Menu
Forums
New posts
Search forums
Members
Current visitors
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Menu
Log in
Register
Install the app
Install
Forums
Archive
Archive
C Programming
Functions taking pointers to different types as arguments
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="Chris Torek" data-source="post: 2398232"><p>No, not according to the original posting anyway. You said that</p><p>one function took a "void *" pointer, the other a "FILE *".</p><p></p><p>Now, go find yourself a Data General Eclipse machine, and compile</p><p>the following source code:</p><p></p><p> #include <stdio.h></p><p></p><p> int get1(void *vp) {</p><p> FILE *fp = vp;</p><p> return fgetc(vp);</p><p> }</p><p></p><p>Observe the assembler-level code (either disassemble the object code,</p><p>or compile to assembly). Note that the assignment "fp = vp" *uses</p><p>a shift instruction*. The assembly code turns out to be identical</p><p>to that for:</p><p></p><p> int get1(unsigned int vp) {</p><p> unsigned int fp = vp >> 1;</p><p> return fgetc(fp);</p><p> }</p><p></p><p>Now compare that to the assembly code for:</p><p></p><p> int get2(void *vp) {</p><p> return gzgetc(vp);</p><p> }</p><p></p><p>Here there is no shift instruction.</p><p></p><p>In other words, assignments from "FILE *" to "void *" require shifts</p><p>(left or right depending on which is the source and which is the</p><p>destination), while assignments from "void *" to "void *" are simply</p><p>bit-for-bit copies. You *must* get the shift instruction, via the</p><p>wrapper, for the version that calls fgetc(), because fgetc() expects</p><p>its argument to be pre-shifted.</p><p></p><p></p><p>The gzgetc() function takes a "void *", and the fgetc() function</p><p>takes a "FILE *" (which is a "struct ... *"). These pointers have</p><p>different formats. The insides of both gzgetc() and fgetc() assign</p><p>values to the data structures to which the pointers point. These</p><p>assignments are hidden, but do occur.</p><p></p><p></p><p>Pointers to functions are *interconvertible*. This is not, at</p><p>least with my definition of "interchangeable", quite the same as</p><p>interchangeable. Consider int and double: we can take an int value,</p><p>convert it to a double, and (on most machines) preserve *all* the</p><p>original values (because int is typically 32 or fewer bits, while</p><p>double has at least 53 bits of mantissa). If we then convert the</p><p>resulting double back to int, we get the original value back --</p><p>but the conversion has changed things internally. The internal</p><p>representations of (int)3 and (double)3.0 are quite different (again,</p><p>on most machines[%] anyway).</p><p>-----</p><p>% The Burroughs A-series stored integers in floating-point format.</p><p>I have some doubts whether anyone could build a working C</p><p>implementation on one of these, even if any are still out there</p><p>to use, but if group did build a C compiler for one, they might</p><p>use the same representation for int and double.</p><p>-----</p><p></p><p>The same holds, in principle, for function pointers in C. The</p><p>standard guarantees that, given any two function types FT1 and FT2</p><p>and function f() of type FT1, the result of:</p><p></p><p> (FT1)(FT2)f</p><p></p><p>is just as useful as the original pointer. The "round trip</p><p>conversion" from FT1 to FT2, and then back to FT1, via the two</p><p>casts, preserves the value. The standard does *not* guarantee that</p><p>the internal representations are the same. Unlike the Eclipse</p><p>example, I do not know of any machines where the conversion really</p><p>does change the representation -- but it is *allowed*, so portable</p><p>code should be sure to cause both conversions. On the Eclipse,</p><p>when dealing with data pointers, both conversions are required;</p><p>code that achieves only one of them -- including incorrect qsort()</p><p>functions, which were one of the canonical examples -- fails at</p><p>runtime.</p><p></p><p>Most modern machines have only one internal representation for</p><p>pointers (the generic byte pointer), which has led people to forget</p><p>all the "interesting" problems that occurred when porting code to</p><p>the Eclipse, or even some of the funny "memory models" of the older</p><p>x86 (only some of which were actually standard-conforming). The</p><p>C standards (C89 and C99 both) do allow for them, though, and with</p><p>the advent of 64-bit CPUs, I suspect some of them will make a</p><p>comeback for a while.</p></blockquote><p></p>
[QUOTE="Chris Torek, post: 2398232"] No, not according to the original posting anyway. You said that one function took a "void *" pointer, the other a "FILE *". Now, go find yourself a Data General Eclipse machine, and compile the following source code: #include <stdio.h> int get1(void *vp) { FILE *fp = vp; return fgetc(vp); } Observe the assembler-level code (either disassemble the object code, or compile to assembly). Note that the assignment "fp = vp" *uses a shift instruction*. The assembly code turns out to be identical to that for: int get1(unsigned int vp) { unsigned int fp = vp >> 1; return fgetc(fp); } Now compare that to the assembly code for: int get2(void *vp) { return gzgetc(vp); } Here there is no shift instruction. In other words, assignments from "FILE *" to "void *" require shifts (left or right depending on which is the source and which is the destination), while assignments from "void *" to "void *" are simply bit-for-bit copies. You *must* get the shift instruction, via the wrapper, for the version that calls fgetc(), because fgetc() expects its argument to be pre-shifted. The gzgetc() function takes a "void *", and the fgetc() function takes a "FILE *" (which is a "struct ... *"). These pointers have different formats. The insides of both gzgetc() and fgetc() assign values to the data structures to which the pointers point. These assignments are hidden, but do occur. Pointers to functions are *interconvertible*. This is not, at least with my definition of "interchangeable", quite the same as interchangeable. Consider int and double: we can take an int value, convert it to a double, and (on most machines) preserve *all* the original values (because int is typically 32 or fewer bits, while double has at least 53 bits of mantissa). If we then convert the resulting double back to int, we get the original value back -- but the conversion has changed things internally. The internal representations of (int)3 and (double)3.0 are quite different (again, on most machines[%] anyway). ----- % The Burroughs A-series stored integers in floating-point format. I have some doubts whether anyone could build a working C implementation on one of these, even if any are still out there to use, but if group did build a C compiler for one, they might use the same representation for int and double. ----- The same holds, in principle, for function pointers in C. The standard guarantees that, given any two function types FT1 and FT2 and function f() of type FT1, the result of: (FT1)(FT2)f is just as useful as the original pointer. The "round trip conversion" from FT1 to FT2, and then back to FT1, via the two casts, preserves the value. The standard does *not* guarantee that the internal representations are the same. Unlike the Eclipse example, I do not know of any machines where the conversion really does change the representation -- but it is *allowed*, so portable code should be sure to cause both conversions. On the Eclipse, when dealing with data pointers, both conversions are required; code that achieves only one of them -- including incorrect qsort() functions, which were one of the canonical examples -- fails at runtime. Most modern machines have only one internal representation for pointers (the generic byte pointer), which has led people to forget all the "interesting" problems that occurred when porting code to the Eclipse, or even some of the funny "memory models" of the older x86 (only some of which were actually standard-conforming). The C standards (C89 and C99 both) do allow for them, though, and with the advent of 64-bit CPUs, I suspect some of them will make a comeback for a while. [/QUOTE]
Verification
Post reply
Forums
Archive
Archive
C Programming
Functions taking pointers to different types as arguments
Top