Coderer
Coderer

Reputation: 27264

Byte width of a value type

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.

Upvotes: 0

Views: 616

Answers (4)

SteinNorheim
SteinNorheim

Reputation: 2207

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.

Upvotes: 3

Tor Haugen
Tor Haugen

Reputation: 19627

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.

Upvotes: 0

Chris J
Chris J

Reputation: 2206

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.

Upvotes: 1

Rauhotz
Rauhotz

Reputation: 8140

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.

Upvotes: 0

Related Questions