|
build in data type bigger than pointer size? |
Martin Kalbfuß
Member #9,131
October 2007
|
Hey, Maybe someone knows if there's a build-in type (C99) which is guaranteed to be bigger than the size of a pointer. I would like to store either a pointer or a number in it. The range of numbers isn't important. The only restriction is, that it shouldn't overlap with the range of addresses a pointer can have. The function taking this kind of parameter should be able to distinguish between those. A type twice as big as intptr_t would be fine. This way I could simply use the negative numbers. Thanks, http://remote-lisp.spdns.de -- my server side lisp interpreter |
Audric
Member #907
January 2001
|
Does it really have to be a native type ? Otherwise I'd use something like: typedef struct { char type; // 0=number 1=address union { void * address; int number; }; } T_FOO;
|
Martin Kalbfuß
Member #9,131
October 2007
|
This way you have to pass in the type, too. I would like to have this working for pointers which are plain numbers and don't have type field. A cast or conversion function isn't a problem. I could hide it behind a macro. Like this: void my_func(magic_type_t val) { if is_pointer(val) { ... } else if is_other(val) { ... } } void my_func((magic_type_t)"bla"); void my_func((magic_type_t)-2);
http://remote-lisp.spdns.de -- my server side lisp interpreter |
Matthew Leverton
Supreme Loser
January 1999
|
1#include <stdio.h>
2#include <stdint.h>
3
4#define SET_MAGIC_NUM(x) (((x) << 1) | 1)
5#define GET_MAGIC_NUM(x) ((x) >> 1)
6#define IS_MAGIC_NUM(x) ((x) & 1)
7
8int main()
9{
10 int x = 42;
11 intptr_t foo = &x;
12
13 intptr_t bar = SET_MAGIC_NUM(42);
14
15 printf("%d %d %d\n", IS_MAGIC_NUM(foo), IS_MAGIC_NUM(bar), GET_MAGIC_NUM(bar));
16
17 return 0;
18}
You'll lose one bit for the integers. |
Thomas Fjellstrom
Member #476
June 2000
|
C99 pseudo code: struct magic_t { char type; uint32_t i; intptr_t p; }; magic_t mk_ptr(intptr_t p) { return (magic_t){ 0, 0, p }; } magic_t mk_int(uint32_t i) { return (magic_t){ 1, i, NULL }; } void my_func(magic_t m) { if(m.type == 0) ... else if(m.type == 1) ... }
-- |
Audric
Member #907
January 2001
|
ML: If a pointer is odd (last bit = 1), it will be mistaken as a number. |
Martin Kalbfuß
Member #9,131
October 2007
|
ML's solution is what I'm looking for. But as Audric said. Isn't the least significant bit of a pointer of importance? http://remote-lisp.spdns.de -- my server side lisp interpreter |
Matthew Leverton
Supreme Loser
January 1999
|
It depends on what you are doing. Anything that points to the beginning of a "variable" will have a zero low bit. If it's pointing inside a string, then it wouldn't work. |
Oscar Giner
Member #2,207
April 2002
|
Thomas Fjellstrom
Member #476
June 2000
|
Yeah, most variables, structs and whatnot are aligned to a word boundary. so theoretically you could use the last 2-3 bits to store info if you wanted, and were careful. Actually the linux kernel is known to use that trick in some locations. Oscar Giner said: One of those pointers will have 1 as low bit. Try compiling with optimizations. GCC is supposed to align variables. -- |
Oscar Giner
Member #2,207
April 2002
|
MSVC10 with optimizations: 003AFDDE, 003AFDDF You don't need to align 1 byte variables to word boundaries for anything. -- |
Audric
Member #907
January 2001
|
ML: It's true that malloc() alway returns aligned addresses (4-byte and 8-byte respectively on 32bit and 64bit systems), but if you look at an array of chars, or individual char fields in a struct (ex: RGB), or local char variables in a function, they don't need to be aligned - even on platforms that are very touchy about alignment, like ARM. |
Thomas Fjellstrom
Member #476
June 2000
|
Oscar Giner said: You don't need to align 1 byte variables to word boundaries for anything. Some architectures don't allow unaligned accesses. And while X86 does allow it, its a lot slower than aligned accesses. Now stick those variables in a struct and give it a try. Audric said: but if you look at an array of chars, or individual char fields in a struct (ex: RGB), or local char variables in a function, they don't need to be aligned - even on platforms that are very touchy about alignment, like ARM. Except now you get stuck with a lot of RMW cycles to change the unaligned variables. -- |
Matthew Leverton
Supreme Loser
January 1999
|
I mentioned there were exceptions. The original question is a hack, and so often you can work within restrictions. char __attribute__ ((aligned (2))) a; char __attribute__ ((aligned (2))) b; Now it's aligned. Problem solved. |
Oscar Giner
Member #2,207
April 2002
|
Thomas Fjellstrom said: Some architectures don't allow unaligned accesses. And while X86 does allow it, its a lot slower than aligned accesses. Now stick those variables in a struct and give it a try. Inside a struct it should be the same, but the compiler will add a padding to the end so the full struct is 4 (or 8) byte aligned (although if the struct only contains chars, this should not be necessary, so a good optimizer won't add any padding in this case). ARM can perfectly access a single byte residing anywhere inside a word, an x86 doesn't suffer from any performance hit from this. The problem comes with data > 1 byte. Your definition of when a variable is aligned or not is wrong. Look at the chart at the end of this page, for example: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/aligned.html -- |
Arthur Kalliokoski
Second in Command
February 2005
|
If you were to "align" byte data, then the next byte to access is unaligned by definition, so what price alignment? They all watch too much MSNBC... they get ideas. |
Matthew Leverton
Supreme Loser
January 1999
|
Arthur Kalliokoski said: If you were to "align" byte data, then the next byte to access is unaligned by definition, so what price alignment? What is the question? If Martin simply wants to distinguish between object pointers and integer values, my solution will work unless somebody is intentionally trying to break it. If he needs to accept pointers to chars, then it requires more careful alignment. And some cases simply wouldn't be possible to support (i.e., subsets of C-strings). If those are common cases that he needs to support, then I'd go with something like Audric has suggested. |
Oscar Giner
Member #2,207
April 2002
|
Who says a pointer to an object cannot have an address ending in 1? 1#include <cstdio>
2#include <vector>
3
4class test
5{
6 char a;
7 char b;
8 char c;
9};
10
11int main()
12{
13 test test_array[10];
14 std::vector<test> test_vector;
15 test_vector.push_back(test());
16 test_vector.push_back(test());
17 test_vector.push_back(test());
18 test_vector.push_back(test());
19
20 test *pointer_to_object;
21
22 pointer_to_object = &(test_array[1]);
23 printf ("pointer_to_object = %p\n", pointer_to_object);
24
25 pointer_to_object = &(test_vector[1]);
26 printf ("pointer_to_object = %p\n", pointer_to_object);
27}
Output: pointer_to_object = 0020F9EF pointer_to_object = 007F2FD3 Again, compiled with MSVC10, with optimizations enabled. -- |
relpatseht
Member #5,034
September 2004
|
Just use the highest bit then if you're worried about the lowest. You'll never get an address that high--that is operating system territory. On x86 for at least Windows, but I think linux as well, every application is only given the lower 2gb of virtual address space. On x64, it is typically the lower 48 bits (off-hand, needs verification). You can use the highest bit to store some information if you want to.
|
Matthew Leverton
Supreme Loser
January 1999
|
I don't know why this bothers you so much. Perhaps you are just being anal over my choice of words. You're contriving a case with an unaligned object using an odd amount of single byte data structs. Throw an int in the struct, and it will magically become aligned. As I've said from the start, this isn't a general purpose solution. However, it can be a valid solution depending on what is trying to be accomplished. relpatseht said: You can use the highest bit to store some information if you want to. But what if I am writing an operating system? |
relpatseht
Member #5,034
September 2004
|
#define SET_MAGIC_NUM(x) ((x) | (1 << (sizeof(intptr_t)*8 - 1))) #define GET_MAGIC_NUM(x) ((x) & (1 << ((sizeof(intptr_t)*8 - 1)-1))) #define IS_MAGIC_NUM(x) ((x) & (1 << (sizeof(intptr_t)*8 - 1))) No alignment problems. Works on all pointers in your program. Of course, it won't work with negative numbers, but neither will ML's solution. If you need negatives, then you really can't use hacks like this at all...
|
Thomas Fjellstrom
Member #476
June 2000
|
Ok, seems I'm wrong, char's aren't aligned on ia-32/amd-64. I thought they were. However, if you intersperse integers into the chars, the ints WILL be aligned to word boundaries. -- |
Peter Wang
Member #23
April 2000
|
A lot of programming language implementations use the trick Matthew described (tag bits).
|
verthex
Member #11,340
September 2009
|
Audric said: Does it really have to be a native type ? Otherwise I'd use something like: typedef struct { Question: When you have a type like, void* address is that only for addresses or is there another use for them?
|
LennyLen
Member #5,313
December 2004
|
verthex said: When you have a type like, is that only for addresses or is there another use for them? http://stackoverflow.com/questions/1025579/when-to-use-a-void-pointer
|
|