25

I was just reading the section of the C FAQ on pointers.

It discusses not being able to use void * pointers to hold function pointers because pointers to data and pointers to functions may have differing sizes on some platforms and void * is only guaranteed be large enough to hold pointers to data.

Can anyone give an example of a platform where pointers to data and pointers to functions actually have differing sizes?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179

6 Answers6

11
> type ppp.c
#include <stdio.h>
#include <stdlib.h>

int global = 0;

int main(void) {
    int local = 0;
    static int staticint = 0;
    int *mall;
    int (*fx)(void);

    fx = main;
    mall = malloc(42); /* assume it worked */
    printf("#sizeof pointer to local: %d\n", (int)sizeof &local);
    printf("#sizeof pointer to static: %d\n", (int)sizeof &staticint);
    printf("#sizeof pointer to malloc'd: %d\n", (int)sizeof mall);
    printf("#sizeof pointer to global: %d\n", (int)sizeof &global);
    printf("#sizeof pointer to main(): %d\n", (int)sizeof fx);
    free(mall);
    return 0;
}
> tcc -mc ppp.c
Turbo C  Version 2.01 ...
warnings about unused variables elided ...
Turbo Link  Version 2.0 ...
> ppp
#sizeof pointer to local: 4
#sizeof pointer to static: 4
#sizeof pointer to malloc'd: 4
#sizeof pointer to global: 4
#sizeof pointer to main(): 2
> tcc -mm ppp.c
> ppp
#sizeof pointer to local: 2
#sizeof pointer to static: 2
#sizeof pointer to malloc'd: 2
#sizeof pointer to global: 2
#sizeof pointer to main(): 4

tcc -mc generates code in the "compact" model; tcc -mm generates code in the "medium" model

pmg
  • 106,608
  • 13
  • 126
  • 198
9

On real-mode x86, code & data is accessed by segment + offset, each a 16-bit quantity. "Near" pointers were 16-bit only and used the current segment, "Far" pointers were 32-bit and specified the segment and offset. For C compilers, there were several different memory models you could choose, with different defaults of near or far pointers for code and data.

For example, the "Medium" memory model used near pointers for data but far pointers for code by default.

I wouldn't be surprised if some modern embedded processors have similar memory models.

Michael
  • 54,279
  • 5
  • 125
  • 144
7

16-Bit PIC microcontrollers (Microchip PIC24 and dsPIC) are examples of Harvard architecture devices with different data and code space pointer sizes. The separate address spaces differ in size - on chip SRAM has a greater chip-area cost that Flash memory, there is much less of it, so data pointers can be smaller.

This is also true of PIC12, PIC16, and PIC18 architectures also, but dsPIC is what I happen to be using currently.

Clifford
  • 88,407
  • 13
  • 85
  • 165
6

Note that POSIX requires pointers to objects and pointers to functions to be the same size:

2.12.3 Pointer Types

All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.

Note: The ISO C standard does not require this, but it is required for POSIX conformance.

Consequently, systems that claim POSIX-compliance will be uniform. If you only target such machines, then you do not have to worry about the differences.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 5
    NB: As of 2013-03-07, this section seems to be missing from POSIX [Data types](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12), though it is still mentioned in the [Rationale](http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_12_03). I've asked for clarification from OpenGroup whether this is a glitch in the web site or a substantive change in POSIX 2013 compared to POSIX 2008. I don't know when I'll receive an answer. – Jonathan Leffler Mar 07 '14 at 16:29
  • 1
    did you ever get a response? – Mitch Jan 27 '15 at 18:50
  • 2
    @Mitch: yes, I got a response back in March 2014. Basically, it is a deliberate change, a response to a bug report. The discussion about it is available at http://austingroupbugs.net/view.php?id=74 where the paragraph cited is removed and revised wording for `dlsym()` is described. Sometime, I need to write it up properly — I've been meaning to do that for most of a year now (and the round tuits have never become available). – Jonathan Leffler Jan 27 '15 at 19:08
5

Machines that use a Harvard Architecture have separate storage for instructions and data, and correspondingly have separate address spaces for instructions and data. In such an architecture, there is no real reason to have the two address spaces (or physical memory backing them) be the same size.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • 1
    It might be better to clarify why this is the case rather than just linking to Wikipedia. – Chris Lutz Sep 24 '09 at 20:32
  • Fair enough; I think the Wikipedia text is pretty informative and thought it was clear enough on its own, but reasonable people may differ. – Stephen Canon Sep 24 '09 at 20:37
  • While this is a good pointer (HA!) for the OP, a Harvard architecture does not necessitate a difference in pointer sizes, the size of the address space does. You can have 2 separate physical memories embedded in a single address space, in which case you may not need to distinguish between the size of void *s and size of other pointers. But I agree that a Harvard architecture machine is a likely place to begin looking for a machine with separate data and function pointers. – Falaina Sep 24 '09 at 20:41
  • 1
    Oh, it certainly doesn't *require* that they have different pointer sizes, it just makes it far more likely, and explains why you might expect a standard to support such things. The only actual examples of this that I have seen are [modified] harvard architectures. – Stephen Canon Sep 24 '09 at 20:43
1

It's a "depends" situation. In C++ I recall that member function pointers are actually two pointers in size, but that may be purely an implementation detail.

In some of the really old pre-PC systems you could also have pointer size depend on what was being referenced (but then you could also have 11bit characters :D )

olliej
  • 35,755
  • 9
  • 58
  • 55
  • 3
    It's virtually impossible to implement a member function pointer in C++ in less than 2 machine words; the reason being that 1) dispatch via member pointer has to be virtual, so you can't just store address of method and 2) it is legal to declare member pointers to forward-declared classes, so you don't know if the class has any virtual methods in advance. – Pavel Minaev Sep 24 '09 at 20:32