4

I've searched quite a bit, but couldn't find anything helpful - but then I'm not sure I'm searching for the right thing.

Is there any scalar defined by the standard that has to be at least as large as a pointer? I.e. sizeof(?) >= sizeof(void*).

I need it because I'm writing a small garbage collector and want something along the lines of this:

struct Tag {
    uint32_t desc:sizeof(uint32_t)*8-2; // pointer to typedescriptor
    uint32_t free:1;
    uint32_t mark:1;
};

I'd prefer something that's valid according to the standard (if we're at it, I was quite surprised that sizeof(uint32_t)*8-2 is valid for the bitfield definition - but VS2010 allows it).

So does size_t fulfill this requirement?

Edit: So after my inclusion of both C and C++ lead to some problems (well and there I thought they would be similar in that regard), I'd actually settle for one of them (I don't really need C++ for this part of the code and I can link C and c++ together so that should work). And C99 seems to be the right standard in this case from the answers.

Voo
  • 29,040
  • 11
  • 82
  • 156
  • C or C++? Could you choose one, or do you want an answer for both? – David Heffernan Mar 27 '11 at 13:11
  • 1
    Why not just `struct Tag { void* desc; int free:1; int mark:1; };`? – aschepler Mar 27 '11 at 13:13
  • @aschepler: Presumably an attempt to minimise memory footprint. – Oliver Charlesworth Mar 27 '11 at 13:16
  • If I understand correctly, it seems that void * will do it. – Pete Wilson Mar 27 '11 at 13:16
  • 3
    You need `#include ` and `CHAR_BIT` instead of `8`. The type `uint32_t` is not guaranteed to be defined in all C99 implementations. `#include ` (you already have for this snippet) and use `uint_least32_t` instead – pmg Mar 27 '11 at 13:16
  • @aschepler: Since structs are usually word size aligned for performance reasons, that would use 8byte instead of 4 on a 32bit machine and 16 instead of 8 on 64bit. Since the Tag is needed for every allocated objected (and every entry in the free list) that's some easily reduced overhead (and has only a small performance hit when the GC runs) – Voo Mar 27 '11 at 13:24
  • @pmg: Just used uint32_t for the fast example, but good to know anyhow. Also interesting that there's a CHAR_BIT definition, I thought one of the only things defined in C (and therefore hopefully in c++ as well) was that a char is always one byte. – Voo Mar 27 '11 at 13:28
  • 2
    `char` and `byte`, in C, are synonyms. What the Standard does not specify is the number of bits in them: it mandates **8 or more** bits in a byte though – pmg Mar 27 '11 at 13:33

2 Answers2

4

You could include <stdint.h> (or <cstdint>) and use uintptr_t or intptr_t.

Since MSVC refuses to support C99, you may need to include <Windows.h> and use ULONG_PTR or LONG_PTR instead. (See C99 stdint.h header and MS Visual Studio)

(Also, please use CHAR_BIT instead of 8.)

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • That's not portable though is it? – David Heffernan Mar 27 '11 at 13:17
  • @David: It's part of C99, though I think the header is `` – John Ledbetter Mar 27 '11 at 13:17
  • @John I thought it was optional. Also not in C++. And only optional in C++11? Or has that changed recently? – David Heffernan Mar 27 '11 at 13:19
  • `[u]intptr_t` types are optional – pmg Mar 27 '11 at 13:20
  • That's exactly what I'm looking for, great. And I think optional C99 should be good enough - at least I'd get a fast error if I used it somewhere where it wouldn't work. – Voo Mar 27 '11 at 13:20
  • under MSVC you want `INT_PTR` or `UINT_PTR` – Necrolis Mar 27 '11 at 13:20
  • @David I don't know if it's part of any C++ standard. The OP would need to clarify his needs, since he tagged it both `C` and `C++`. – John Ledbetter Mar 27 '11 at 13:21
  • It is optional because the language standard(s) can't require an int type big enough to hold a pointer. Could be a problem on systems with a segmented memory architecture. – Bo Persson Mar 27 '11 at 13:33
  • I gave a +1, although I'm not convinced that `CHAR_BIT` is needed when talking about how many bits to a byte. Sure, DEC had 12-bit bytes, and even today you'll see standards refer to octets. But, really, we aren't about to see the resurgence of nonstandard bytes. – Max Lybbert Mar 27 '11 at 13:51
  • 1
    @Max: http://stackoverflow.com/questions/2098149/what-platforms-have-something-other-than-8-bit-char. Really it depends what the code is for - most apps are never going to run on a DSP, or for that matter any "embedded" target, but general utility code might. Making the assumption simply because `8` is faster to type than `CHAR_BIT` is what Larry Wall would call "false laziness". Making it because you're doing I/O where bytes really need to be octets is fine, it's easy enough to document and/or check at compile-time. – Steve Jessop Mar 27 '11 at 14:17
  • 1
    @Max: Well I suggested `CHAR_BIT` because I initially mistaken OP wants a bit field with `8*sizeof(void*)-2` bytes :). With `CHAR_BIT` it is clear with that 8 is for. And it isn't a bad thing to make it more portable, right? ;) – kennytm Mar 27 '11 at 14:18
  • Well I just didn't know that C allowed anything but 8bit/byte in the first post (and that although I've read Knuth and he discusses that in the beginning of book1~), I'm always thankful for more tips - sure the code won't run anywhere where it'd matter, but hey, it can't harm. And considering that a pointer is really sizeof(void*) * CHAR_BIT long, using CHAR_BIT is really the correct solution I'd think. – Voo Mar 27 '11 at 15:34
  • `intptr_t` works just fine in Visual Studio 2010. What version are you using? – Cody Gray - on strike Mar 27 '11 at 15:41
  • OK, I'm convinced you need the documentation properties of a constant. If I see the magic number 8, I might think of several things that are 8-somethings, and bits-in-a-byte is only one of those. – Max Lybbert Mar 28 '11 at 15:02
1

C99 has the optional uintptr_t in <stdint.h>which guarantees that you can convert between a uintptr_t and a pointer value, though it doesn't say anything about any operations on integer.

Generally, on common platforms a void* is the same as any other pointer and converting a pointer to an integer, manipulating that integer and converting it back to a pointer yields well defined resultes, but C does not guarantee this so you'll have to know the compilers/platform you want to target.

Best you probably can do is use the above mentioned uintptr_t if you have a C99 compiler, or compile a program on the target platform which checks whether sizeof(void*) is equal to any of the sizeof unsigned short,int,long,long long and generate a header file where you typedef your own uintptr according to what the program found out.

nos
  • 223,662
  • 58
  • 417
  • 506