Calculate Length in bytes of an object [duplicate] - c#

I would normally do this in my C++ code:
int variable = 10;
int sizeOfVariable = sizeof(variable); //Returns 4 for 32-bit process
But that doesn't seem to work for C#. Is there an analog?

The sizeof operator in C# works only on compile-time known types, not on variables (instances).
The correct example would be
int variable = 10;
int sizeOfVariable = sizeof(int);
So probably you are looking for Marshal.SizeOf which can be used on any object instances or runtime types.
int variable = 10;
int sizeOfVariable = Marshal.SizeOf(variable);
See here for more information

.NET 4.0 onwards:
if (Environment.Is64BitProcess)
Console.WriteLine("64-bit process");
else
Console.WriteLine("32-bit process");
Older versions of .NET framework:
public static bool Is64BitProcess
{
get { return IntPtr.Size == 8; }
}
(From your example I'm assuming you want to do this to determine the bitness of the process, which may in fact not be what you are trying to do!)

There are only a few standard situations where you'll want to do it:
int x = sizeof(T) // where T is a generic type
sadly it doesn't work :-)
int x = Marshal.SizeOf(T) // where T is a generic type
it does work except for char and bool (Marshal.SizeOf(typeof(char)) == 1 instead of 2, Marshal.SizeOf(typeof(bool)) == 4 instead of 1)
int x = sizeof(IntPtr);
it doesn't work, but you can do it as
int x = Marshal.SizeOf(typeof(IntPtr));
or, better
int x = IntPtr.Size;
All the other basic types (byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, bool, char) have a fixed length, so you can do sizeof(int) and it will always be 4.

You can use the Marshal.SizeOf() method, or use sizeof in unmanaged code:
Console.WriteLine(Marshal.SizeOf(typeof(int)));
This prints 4 on ideone.
Here is a link to Eric Lippert's blog describing the difference between the two sizeof options.

You can use sizeof on user-defined structs in unsafe contexts but unlike Marshal.SizeOf it does not support boxed objects

Related

Why do the SByte and Int32 CompareTo() methods behave differently?

If you run the following code:
SByte w = -5;
Console.WriteLine(w.CompareTo(0));
Int32 x = -5;
Console.WriteLine(x.CompareTo(0));
SByte y = 5;
Console.WriteLine(y.CompareTo(0));
Int32 z = 5;
Console.WriteLine(z.CompareTo(0));
then you get the following output:
-5
-1
5
1
Why do these methods with the same name that have almost identical descriptions in the MSDN documentation behave so differently?
Because the SByte.CompareTo() is implemented like
return m_value - value;
so a simple subtraction. This works because the m_value is converted automatically to int, and any possibile combination of values is "legal" with int.
With two Int32 this can't be done, because for example Int32.MinValue.CompareTo(Int32.MaxValue) would become Int32.MinValue - Int32.MaxValue that would be outside the int range, and in fact it is implemented as two comparisons:
if (m_value < value) return -1;
if (m_value > value) return 1;
return 0;
in general
The only important "thing" of the returned value of a CompareTo is its sign (or if it is 0). The "value" is irrelevant. The return value of 1, 5, 500, 5000, 5000000 of CompareTo() are the same. CompareTo can't be used to measure "distance" between numbers. So both implementations are equivalent.
It is totally wrong to do:
if (someValue.CompareTo(someOtherValue) == -1)
you must always
if (someValue.CompareTo(someOtherValue) < 0)
why the SByte.CompareTo is built that way
SByte.CompareTo is implementing a "branchless" comparison (there are no ifs in the code, the flow of code is linear). Processors have problems with branches, so branchless code could be faster than "branchful" code, so this microoptimization. Clearly SByte.CompareTo could have been written as Int32.CompareTo.
why any negative value is equivalent to -1 (and any positive value is equivalent to +1)
This is probably something that is derived directly from the C language: the qsort function for example to compare items uses a user-defined method that is like:
Pointer to a function that compares two elements.
This function is called repeatedly by qsort to compare two elements. It shall follow the following prototype:
int compar (const void* p1, const void* p2);
Taking two pointers as arguments (both converted to const void*). The function defines the order of the elements by returning (in a stable and transitive manner):
return value meaning
<0 The element pointed to by p1 goes before the element pointed to by p2
0 The element pointed to by p1 is equivalent to the element pointed to by p2
>0 The element pointed to by p1 goes after the element pointed to by p2
how is the .CompareTo implemented in other primitive types?
SByte, Byte, Int16, UInt16, Char all use the subtraction "method", while Int32, UInt32, Int64, UInt64 all use the if "method".
Looking at the source for these two methods, they are implemented differently:
public int CompareTo(sbyte value)
{
return (int)(this - value);
}
vs
public int CompareTo(int value)
{
if (this < value)
{
return -1;
}
if (this > value)
{
return 1;
}
return 0;
}
But none of this matters, since the sign of the returned value is the only thing that you should be checking.

sizeof() operator for types

I would normally do this in my C++ code:
int variable = 10;
int sizeOfVariable = sizeof(variable); //Returns 4 for 32-bit process
But that doesn't seem to work for C#. Is there an analog?
The sizeof operator in C# works only on compile-time known types, not on variables (instances).
The correct example would be
int variable = 10;
int sizeOfVariable = sizeof(int);
So probably you are looking for Marshal.SizeOf which can be used on any object instances or runtime types.
int variable = 10;
int sizeOfVariable = Marshal.SizeOf(variable);
See here for more information
.NET 4.0 onwards:
if (Environment.Is64BitProcess)
Console.WriteLine("64-bit process");
else
Console.WriteLine("32-bit process");
Older versions of .NET framework:
public static bool Is64BitProcess
{
get { return IntPtr.Size == 8; }
}
(From your example I'm assuming you want to do this to determine the bitness of the process, which may in fact not be what you are trying to do!)
There are only a few standard situations where you'll want to do it:
int x = sizeof(T) // where T is a generic type
sadly it doesn't work :-)
int x = Marshal.SizeOf(T) // where T is a generic type
it does work except for char and bool (Marshal.SizeOf(typeof(char)) == 1 instead of 2, Marshal.SizeOf(typeof(bool)) == 4 instead of 1)
int x = sizeof(IntPtr);
it doesn't work, but you can do it as
int x = Marshal.SizeOf(typeof(IntPtr));
or, better
int x = IntPtr.Size;
All the other basic types (byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, bool, char) have a fixed length, so you can do sizeof(int) and it will always be 4.
You can use the Marshal.SizeOf() method, or use sizeof in unmanaged code:
Console.WriteLine(Marshal.SizeOf(typeof(int)));
This prints 4 on ideone.
Here is a link to Eric Lippert's blog describing the difference between the two sizeof options.
You can use sizeof on user-defined structs in unsafe contexts but unlike Marshal.SizeOf it does not support boxed objects

Operator ">" cannot be applied to type 'ulong' and 'int'

I'm curious to know why the C# compiler only gives me an error message for the second if statement.
enum Permissions : ulong
{
ViewListItems = 1L,
}
public void Method()
{
int mask = 138612833;
int compare = 32;
if (mask > 0 & (ulong)Permissions.ViewListItems > 32)
{
//Works
}
if (mask > 0 & (ulong)Permissions.ViewListItems > compare)
{
//Operator '>' cannot be applied to operands of type 'ulong' and 'int'
}
}
I've been experimenting with this, using ILSpy to examine the output, and this is what I've discovered.
Obviously in your second case this is an error - you can't compare a ulong and an int because there isn't a type you can coerce both to. A ulong might be too big for a long, and an int might be negative.
In your first case, however, the compiler is being clever. It realises that const 1 > const 32 is never true, and doesn't include your if statement in the compiled output at all. (It should give a warning for unreachable code.) It's the same if you define and use a const int rather than a literal, or even if you cast the literal explicitly (i.e. (int)32).
But then isn't the compiler successfully comparing a ulong with an int, which we just said was impossible?
Apparently not. So what is going on?
Try instead to do something along the following lines. (Taking input and writing output so the compiler doesn't compile anything away.)
const int thirtytwo = 32;
static void Main(string[] args)
{
ulong x = ulong.Parse(Console.ReadLine());
bool gt = x > thirtytwo;
Console.WriteLine(gt);
}
This will compile, even though the ulong is a variable, and even though the result isn't known at compile time. Take a look at the output in ILSpy:
private static void Main(string[] args)
{
ulong x = ulong.Parse(Console.ReadLine());
bool gt = x > 32uL; /* Oh look, a ulong. */
Console.WriteLine(gt);
}
So, the compiler is in fact treating your const int as a ulong. If you make thirtytwo = -1, the code fails to compile, even though we then know that gt will always be true. The compiler itself can't compare a ulong to an int.
Also note that if you make x a long instead of a ulong, the compiler generates 32L rather than 32 as an integer, even though it doesn't have to. (You can compare an int and a long at runtime.)
This points to the compiler not treating 32 as a ulong in the first case because it has to, merely because it can match the type of x. It's saving the runtime from having to coerce the constant, and this is just a bonus when the coercion should by rights not be possible.
It's not the CLR giving this error message it's the compiler.
In your first example the compiler treats 32 as ulong (or a type that's implicitly convertible to ulong eg uint) whereas in your second example you've explicitly declared the type as an int. There is no overload of the > operator that accepts an ulong and an int and hence you get a compiler error.
rich.okelly and rawling's answers are correct as to why you cannot compare them directly. You can use the Convert class's ToUInt64 method to promote the int.
if (mask > 0 & (ulong)Permissions.ViewListItems > Convert.ToUInt64(compare))
{
}

C# 0 (minus) uint = unsigned result?

public void Foo(double d){
// when called below, d == 2^32-1
...
}
public void Bar(){
uint ui = 1;
Foo( 0 - ui );
}
I would expect both 0 and ui to be promoted to signed longs here.
True, with the 0 literal it is knowable at compile time that a cast to uint is safe,
but I suppose this all just seems wrong. At least a warning should be issued.
Thanks!
Does the language spec cover a semi-ambiguous case like this?
Why would anything be promoted to long? The spec (section 7.8.5) lists four operators for integer subtraction:
int operator-(int x, int y);
uint operator-(uint x, uint y);
long operator-(long x, long y);
ulong operator-(ulong x, ulong y);
Given that the constant value 0 is implicitly convertible to uint, but the uint value ui is not implicitly convertible to int, the second operator is chosen according to the binary operator overload resolution steps described in section 7.3.4.
(Is it possible that you were unaware of the implicit constant expression conversion from 0 to uint and that that was the confusing part? See section 6.1.9 of the C# 4 spec for details.)
Following section 7.3.4 (which then refers to 7.3.5, and 7.5.3) is slightly tortuous, but I believe it's well-defined, and not at all ambiguous.
If it's the overflow that bother you, would expect this to fail as well?
int x = 10;
int y = int.MaxValue - 5;
int z = x + y;
If not, what's really the difference here?
It's the int that is being cast to uint to perform substraction from 0 (which is implicitly interpreted by the compiler as uint). Note that int to uint is an implicit conversion hence no warning. There is nothing wrong with your code... except that uint is not CLS-compilant. You can read why here. More info on CLS-compilant code on MSDN
In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.
http://msdn.microsoft.com/en-us/library/aa691376(v=vs.71).aspx
Technically, doing the following:
double d = checked(0-ui);
Will result in a throw of System.OverflowException which is perhaps what you are expecting, but according to the spec since this is not checked the overflow is not reported.

Byte to integer in C#

I am reading a row from a SQL Server table. One of the columns is of type tinyint.
I want to get the value into an int or int32 variable.
rdr.GetByte(j)
(byte) rdr.GetValue(j)
...seems to be the only way to retrieve the value. But how do I get the result into an int variable?
int value = rdr.GetByte(j);
An explicit cast is not required, because a byte to int is a widening conversion (no possibility of data loss).
See the documentation for BitConverter.ToInt32 (contains more examples):
byte[] bytes = { 0, 0, 0, 25 };
// If the system architecture is little-endian (that is, little end first),
// reverse the byte array.
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
// Output: int: 25
Assigning a byte to an int works:
int myInt = myByte;
But maybe you're getting an exception inside IDataRecord.GetByte, in which case you should check that the index you're using to access the data record really points to a tinyint column. You can check the type returned from GetValue. It should be a byte for a tinyint column.
Trace.Assert(rdr.GetValue(j).GetType() == typeof(byte));
Another option is to forego the fragile numeric index altogether:
int myInt = rdr.GetByte(rdr.GetOrdinal(TheNameOfTheTinyintColumn))
(int)rdr.GetByte(j)
Casting the byte to int should work just fine:
int myInt = (int) rdr.GetByte(j);
Since C# supports implicit conversions from byte to int, you can alternatively just do this:
int myInt = rdr.GetByte(j);
Which one you choose is a matter of preference (whether you want to document the fact that a cast is taking place or not). Note that you will need the explicit cast if you want to use type inference, or otherwise myInt will have the wrong type:
var myInt = (int) rdr.GetByte(j);
Quick tidbit I ran into as a kind of corner case. If you have an object type that is of type System.Byte, you can not directly cast to int. You must first cast to a byte, then cast to an int.
public int Method(object myByte)
{
// will throw a cast exception
// var val = (int)myInt;
// will not throw a cast exception
var val = (int)((byte)myInt)
return val;
}
Method((byte)1);
This is similar to Stephen Cleary's comment on the accepted answer, however I am required to specify the size of the int. This worked for me:
int value = Convert.ToInt32(rdr.GetValue(j));
(And it also provided backward compatibility with a database column using an int.)

Categories

Resources