If an arbitrary IntPtr
is received in .NET (C#), is it possible to determine if it is pointing to a 32-bit or 64-bit float and safely convert it to the .NET float
type? Or is explicit knowledge of the type required?

- 28,773
- 8
- 68
- 104

- 5,610
- 13
- 81
- 138
-
Is that a pointer to the value or a pointer to a boxed value? Or is the value stored in the `IntPtr` instead of the pointer? – Guffa Aug 31 '15 at 15:28
-
What are you trying to achive by this? – xxbbcc Aug 31 '15 at 15:29
-
@HansPassant are you talking about converting the memory address that the pointer holds to a float or double? IntPtr's size is different, but what it points to is a single byte in memory (first byte), the arbitrary number of following bytes requires knowledge of the data its pointing to... – Ron Beyer Aug 31 '15 at 15:32
-
Guffa, xxbbcc IntPtr is pointer to native float – denfromufa Aug 31 '15 at 15:37
-
@denfromufa Is it 32-bit float (`float`) or 64-bit float (`double`)? You need to know ahead of time. – xxbbcc Aug 31 '15 at 15:37
-
@xxbbcc this is what the code should determine, ideally also 16/128 bit – denfromufa Aug 31 '15 at 15:41
-
@denfromufa You _cannot_ do that without additional information - an `IntPtr` doesn't carry that information. – xxbbcc Aug 31 '15 at 15:43
-
Do you also want to be ready if the value is passed as a string? I'm just asking for completeness... – Luaan Aug 31 '15 at 15:52
-
string is a different story – denfromufa Aug 31 '15 at 15:57
4 Answers
IntPtr
is never a float
. IntPtr
is a pointer. Do not use IntPtr
for values, ever - it is only for pointers. I've seen quite a few attempts at interop using IntPtr
for values, but that's a terrible idea, always.
This kind of implies interoperating with an unmanaged environment - and doing that usually means losing pretty much all type safety - all that's left is your discipline. There is no meta information to go by, you must know the proper types of everything. There's a reason why you need all those header files - short of reverse engineering, there is no way to know what a functions arguments (or even the calling convention) are.
Even if you are being given a real pointer (and not just a value masked as a pointer), you have no way of knowing the data type of what's being given to you - it's not anywhere in the unmanaged interop contract.
Even if you really are dealing with a pointer to a value that can only ever be either a float
or a double
, there is no way to know how many bytes you are being passed - the information simply isn't there; just a single number - the memory pointer. There is no type information, there isn't even any length information.
It's times like these where you really appreciate just how simple .NET interop is - all those issues are taken care of behind the scenes.

- 62,244
- 7
- 97
- 116
-
@Guffa That's my guess, too, but the question is worded poorly to conclude that. – xxbbcc Aug 31 '15 at 15:30
No, there's no way to magically determine what a pointer points to - when you receive an IntPtr
, all you get is the memory address - you need to know before reading data from that address how many bytes to read and how to treat those bytes.
If it's possible that the pointer points to data of different sizes, you'll need extra information that describes the data pointed by the pointer.

- 16,930
- 5
- 50
- 83
In the most general case, no it isn't possible. The first four bytes of an eight byte (double precision) value have some meaning when interpreted as if they were a single precision value.
However, if you have some additional knowledge (e.g. the values always fall within a certain range / are always finite) then you may be able to differentiate between "four bytes are a single precision value" and "four bytes are a partial read of a double precision value". It's going to need a lot of luck (regarding the restrictions on the data you expect to receive) to actually turn this into a detection algorithm.
In some cases, you may be able to infer size from the pointer alignment. Four byte alignment is definitely not a double precision value. Eight byte alignment can be either precision, though, so this isn't reliable. But it may be useful to save you from reading extra bytes beyond the edge of a page and causing an access violation.
If you want to head down this path (being aware that for some data, you might not be able to decide for sure, and maintenance is not going to be fun), you can use Marshal.Copy
to grab the data into a byte array, and then do bit tests on that as well as BitConverter
to interpret them as floating-point values of different precisions. Be sure to get familiar with IEEE encoding of floating-point numbers, biased encoding of exponents, etc.
At the other extreme, if you're being passed an array of data and given only the length in bytes, but not the number of elements/size of each element, you have a very good chance of identifying the repetition pattern and deducing the precision.
Bottom line: This isn't a good way to build software for deployment. But if you are writing throw-away code to deal with a particular dataset, and the code will never leave your hands, there's a chance you can succeed.

- 277,958
- 43
- 419
- 720
-
4Come on, this is incredibly bad advice - imagine trying to maintain code that results from this. You usually have high-quality answers, I'm surprised you posted this. – xxbbcc Aug 31 '15 at 15:44
-
2@xxbbcc: I wrote it to counter *wrong* comments such as yours that say it is completely impossible. Yes, it is valid to advise against it from a maintainability perspective. So go ahead and comment or answer that. Personally I'll let the OP judge maintainability by how much work it takes him to write the code in the first place -- some lessons have to be learned that way. – Ben Voigt Aug 31 '15 at 15:47
-
Even you say that in the general case it's impossible so why are you calling my comment bad? The kind of restrictions you place on your own (very brittle) solution makes it usable in a very narrow case and it's dangerous - anything that's accidentally out of that range will lead to very-hard-to-find errors. – xxbbcc Aug 31 '15 at 15:50
-
@xxbbcc: Because no one ever uses the entire set of possible values for floating-point numbers, so the most general case isn't actually very interesting. – Ben Voigt Aug 31 '15 at 15:51
-
2@xxbbcc Especially when this is exactly the kind of code that tends to "usually work", and horribly breaks down otherwise, almost impossible to debug. – Luaan Aug 31 '15 at 15:53
-
@xxbbcc: There's no reason to run into access violations, if you actually pay attention to alignment. – Ben Voigt Aug 31 '15 at 15:53
-
@BenVoigt access viloation was just an example. I may take back the -1 if you add some strongly-worded warning to your answer, though, because I fundamentally agree with the technical ponts you made, just not the fact that it's offered as _correct_ advice. (Well, your reputation will make it look like correct advice.) – xxbbcc Aug 31 '15 at 15:55
-
@BenVoigt I took back the downvote since you edited the answer quite a bit and added that last paragraph, although I still think it's poor advice. – xxbbcc Aug 31 '15 at 16:11
Without knowing anything more about the value that it points to, it's not possible to determine the type. The best that you could do would be to examine the 32 first bits to determine if it is a bit pattern that is actually used in the 32 bit floating point format. There are a few bit patterns that are unused, so if you find one of those you know that it has to be a 64 bit number, otherwise you still don't know.
If you know something about the range of numbers that the data can have, it could actually be possible to determine the format. If you for example know that the exponent is limited to a few values, you may be able to determine if it has an 8 bit exponent (32 bit number) or an 11 bit exponent (64 bit number).

- 687,336
- 108
- 737
- 1,005