0

Can the size vary (for a pointer) if the data type is not an integer? I know that in a 32 bit environment the size will be 4 bytes for an integer. What about other data types

user3315144
  • 33
  • 1
  • 3
  • 7
  • Just don't rely on magic numbers inside your code but on `sizeof` (or guaranteed width types like `uint32_t` from `stdint.h`) – Jack Feb 16 '14 at 23:28

4 Answers4

1

C is a language used in very different environments, some of them defy our preconceptions about computers...

Another important difference is data pointers vs function pointers: Even if all your data pointers are the same size, you can still have void(*)(void) of different size. That is probably more frequent than a different size between int* and char*, for example.

About your question:

Can the size vary (for a pointer) if the data type is not an integer?

Yes. The C language only assures that void* has the same size as char*. Also, all struct pointers will have the same size. Other pointer types may have different sizes.

That said, most usual environments (Windows, Linux, OS X) has every pointer type of the same size: 4 for 32-bits and 8 for 64-bits.

Well, except MS-DOS / Win16. But who uses that any more? ;-) And even then the difference in size was not about the type pointed to, but the farness of the pointer. And whether it points to data or code, of course.

UPDATE: Let me cite the C99 standard, 6.2.5, para 26 (emphasis mine):

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • [On a POSIX platform `void(*)(void)` is required to be convertible to `void*`.](http://stackoverflow.com/a/12359083/412080) – Maxim Egorushkin Feb 16 '14 at 23:38
  • @MaximYegorushkin: True... And every other function pointer type should also be converted to that. And in Win32/Win64 all pointers are guaranteed to be of the same size. But, alas, the OP didn't specify the architecture. – rodrigo Feb 16 '14 at 23:40
  • `Yes. The C language only assures that void* has the same size as char*` No: the standard guarantees that _every_ (data) pointer type is convertable to and fro (void*). Since c89, IIRC – wildplasser Feb 16 '14 at 23:41
  • @wildplasser: Please see my updated answer with reference to the C99 standard. – rodrigo Feb 16 '14 at 23:45
  • So: you are learning fast ... – wildplasser Feb 16 '14 at 23:47
  • @wildplasser: Which (weakly) implies that `void*` is at least as big as any other object pointer type, since converting from `foo*` to `void*` and back to `foo*` is guaranteed to yield the original value. (Unless there are extra bits that don't contribute to the representation; an implementation that makes `int*` bigger than `void*` *could* be conforming, but it would almost have to be deliberately perverse.) – Keith Thompson Feb 16 '14 at 23:56
  • _Very_ weakly, I suppose. In the MS-DOS days, pointers could still be represented in 16 bits and anhanced/cast when needed, just by "adding" the proper segment prefix, IIRC. (Bill Gates got rich by introducing this braindamage ...) – wildplasser Feb 17 '14 at 00:05
  • BTW: I am not sure wether it was MS or Borland who invented this _near_ / _far_ pointer nightmare stuff. – wildplasser Feb 17 '14 at 00:13
  • In practice, no (sane) modern compiler is going to make `sizeof(void*) != sizeof(void(*)())`. The distinction between near and far pointers that @wildplasser points out (segment:offset in x86/x64, bank:offset in a lot of other architectures) is applicable to pointers to data, too. – sqykly Feb 17 '14 at 00:15
  • @wildplasser: I'd bet that it was Intel. All that madness came naturally from the hardware architecture. How would you program a 286 in real mode? Would you do anything different? – rodrigo Feb 17 '14 at 00:16
  • @sqykly: In MS-DOS compilers, there were memory models where `sizeof(void*)==16` but `sizeof(void(*)())==32` and vice versa. If that qualifies as modern or sane is up to the reader. – rodrigo Feb 17 '14 at 00:17
  • @wildplasser it was neither. Near and far pointers are a machine concept that was introduced as the memory requirements of programs outgrew the address space of the processor's word size. A near pointer was the size of a machine word, a far pointer was bigger, usually the size of the address bus. Intel did something crazy with segments, though, so the address bus was 20 bits, but a far pointer was 32. – sqykly Feb 17 '14 at 00:19
  • @rodrigo modern is also an important word there. – sqykly Feb 17 '14 at 00:20
  • It certainly was not intel. Intel did not produce compilers at that time. MS / Borland were in a rat-race. – wildplasser Feb 17 '14 at 00:20
  • @wildplasser the compiler has nothing to do with it, aside from needing to deal with it somehow. As for 32 bit far pointers, yes it definitely was intel. – sqykly Feb 17 '14 at 00:22
  • @sqykly: near/far pointers are _not_ a machine concept. It were compiler vendor's artifacts, inspired by the segmented architecture. – wildplasser Feb 17 '14 at 00:23
  • @wildplasser I know 4 assembly languages, and all of them make a distinction between near and far pointers. None of them is MS or Borland. 65x was around since before MS existed, dunno about Borland. They use near and far pointers because the machine instructions they emit operate on near and far pointers. Perhaps "machine concept" was nebulous, so that's about as specific as I can get. – sqykly Feb 17 '14 at 00:29
  • I am not talking about assembly, I am talking about C, and how the different-sizes pointers had to be expressed in its syntax. – wildplasser Feb 17 '14 at 00:32
  • @wildplasser "had to be expressed" is precisely what my point is, no more, no less. They absolutely had to include the concept because they needed to make the machine code they produced make that distinction for the architecture, which is why I make reference to assembly languages; assembly languages don't have contrived artifacts or abstractions, they have machine concepts only. The only thing they could have done differently is call them "long" and "short" or something, but those names were taken. – sqykly Feb 17 '14 at 00:37
0

You can't rely on any size except that char is of size 1. All other datatypes only have minimal ranges that have to be representable. You can't even rely on 1 byte = 8 bit. You should use sizeof if you need to know the size of a datatype or CHAR_BIT to get the number of bits in a byte.

Juri Robl
  • 5,614
  • 2
  • 29
  • 46
  • Can you explain what you mean when you say that 1 byte is not necessarily 8 bits, in the context of C programming? Can you give an example of this? –  Feb 16 '14 at 23:35
  • 2
    See UTF-9 and the PDP-10 architecture. On systems with other native bit-sizes, the C language maps 'char' to its native word size. – woolstar Feb 16 '14 at 23:38
  • I think it is a bit too hard to say that you cannot rely on `CHAR_BIT` being 8. The C language does not force that, true. But most usual environments, particularly those where people are learning will comply with that. Forcing beginners to consider fringe portability issues that probably will never see in real life will just scare them... – rodrigo Feb 16 '14 at 23:38
  • 2
    I think you should be at least aware of the possibility that there are other architectures where your code might not work. And to use `CHAR_BIT` instead of 8 is enough most of the time to make it portable. – Juri Robl Feb 16 '14 at 23:39
  • 1
    @JuriRobl: Portability to exotic platforms (those where `CHAR_BIT!=8`) is not as easy. You may have trap integer representations, negatives not in modulo-2, a void pointer where not every bit is 0, pointers of different sizes, floating pointers that do not follow IEEE 754, non-ASCII character sets, and many more things I am not aware of... – rodrigo Feb 16 '14 at 23:51
  • 1
    I think you mean negatives not in *2's-complement*, and a *null* pointer where not every bit is 0, and *floating-point* (not pointers) that don't follow IEEE 754. With a little care, it's not hard to write code that's reasonably robust in the presence of all those variations, as long as you avoid making assumptions. – Keith Thompson Feb 17 '14 at 00:06
  • 1
    @KeithThompson: Yes to all your corrections (I think I need some sleep...). The biggest problem with writing with all that in mind is that I cannot test it! It would be nice a _deliberately perverse torture interpreter_ for the C language, where every assumption not required by the language would not hold. Then we could make a difference between the truly portable and the just lucky. – rodrigo Feb 17 '14 at 00:14
  • @rodrigo: To oversimplify the issue, sometimes the trick is *not* to keep all that in mind. How is the null pointer represented? Who cares? How are negative integers represented? As negative integers; that's all you really need to know. And so forth. – Keith Thompson Feb 17 '14 at 02:01
0

There is no requirement in the standard for pointers to different types to be of the same type. However, all pointers must be convertible to void* and back. Which means a pointer size cannot be larger than that of void* because the latter is the most generic pointer.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
-3

No, the pointer size will be the same (32 bits in this case), whatever is pointed to.

pscs
  • 642
  • 4
  • 10
  • @M28: Well, member function pointers are not real pointers, despite its name. And they do not exist in C. – rodrigo Feb 16 '14 at 23:35
  • 3
    Not true. C allows pointers to different types to be different sizes, and that size is implementation defined. – Ed S. Feb 16 '14 at 23:38