views:

154

answers:

4

I'd like to pass a value type to a function and set it to a repeating bit pattern (FF, AA, etc.) across the entire width of the variable. Right now, I'm passing the value with

void foo(T val) where T : struct

so I can use any value type. The problem is, the compiler won't let me use sizeof(T), because T could be a reference type (except that it can't, thanks to the "where" constraint). I could hard code all the value types and check against them myself, but that obviously seems like overkill. Is there a simpler way to do this?

Just to clarify: if I pass a byteInt64, I want to set it to 0xFFFFFFFF.

I tried Convert.ChangeType(0xFFFFFFFF, typeof(T)), but it throws if val is e.g. a Char. I could solve the problem by a) figuring out how wide the type-parameter is and "building" a big-enough value to stuff in, b) figuring out how to accept any value type (and only value types), such that sizeof() would work, or c) figuring out how to automagically truncate 0xFFFFFFFF down to the correct width for the variable.

A: 

You could use binary serialization to get the size, but you have to serialize two arrays of the object, one with two elements, one with one element and subtract the one size from the other to remove the serialization overhead. Beware of types like System.Decimal, that have different serialized lengths for different values.

Rauhotz
+2  A: 

Can you use the Marshal.SizeOf method?

http://msdn.microsoft.com/en-us/library/y3ybkfb3.aspx

EDIT: NB! Read Tor Haugen's comment prior to actually doing this.

norheim.se
I'm pretty sure this will get me what I need, *but* now I'm running into the problem that unsigned types throw on Convert.ChangeType if the supplied pattern would set the highest (sign) bit. It's better than nothing, though.
Coderer
If you are doing unmanaged programming anyway (which you seem to be doing), it would probably be easiest to lock the struct, get the pointer to it, and simply fill it byte by byte. Just make sure that your struct doesn't contain any reference types, or types that contain reference types etc...
norheim.se
Beware Mashal.SizeOf() - it returns the size of the type after marshalling, which is not always the size allocated in the runtime. If you need the size for filling a bit pattern in the runtime, it's the latter you need.
Tor Haugen
+1  A: 

You could also cast -1 as whatever you are handing through. No matter the length of the variable, -1 is always all F's. As long as you are using primitive types, this should never really cause too much of an issue.

A quick explanation of why this works:

All integers in a system are held in 2's complement notation. This means negative numbers aren't just the number with a sign bit. To create a 2's complement, you simply flip all the bits and add 1.

ergo:

-1 = not (1) + 1

so

0000 0001 > 1111 1110 > 1111 1111 = 0xFF

This will always give you all 1's for any length item.

EDIT:

use the sizeof operator to get the size of the type in bytes, use typeof to get the type, then I would use bit shifting in a loop to fill the item sooo...

for (int i = 0; i < sizeof(typeof(input)); i++) 
{
  input = (input << 8) | Ox<Pattern>
}

please forgive my syntactic errors, been a while, but that should do what you want.

Chris J
Right, but FF is just an example -- notice I also listed AA; I might want DEDEDE or something else like that; I just want to be able to "fill" the whole width with an arbitrary pattern.
Coderer
Thanks for the refresher on 2's complement - it's been a while. To solve my negative problem, I tried to set the pattern, then if it fails, I set (negative) 2's complement of the value, such that it will be stored the same as the (greater than 0x8000...) pattern would have been. If that makes sense.
Coderer
A: 

Hi Coderer

I thought I was onto something - sizeof() will work for structs, but only in unsafe blocks. So I tried:

// compile with /unsafe
public unsafe void Foo<T>(T val) where T : struct
{
    // Works!
    int size1 = sizeof(SomeStruct);
    // Doesn't work, alas
    int size2 = sizeof(T);
}

It seems sizeof has an issue with generic type parameters. So no go.

As I commented in norheim.se's answer, you should be aware that Marshal.SizeOf() won't necessarily give you the size of your type in the runtime, so I wouldn't recommend it.

Risking ridicule for unelegance, I would honestly consider a simple switch statement. If your value types will be stock ints, longs, bytes etc, there's a manageable number of possibilities. And you should keep in mind that setting a bit pattern might be a different task depending on whether the type is signed or not! Switching will make it easy to deal with suchlike.

Tor Haugen