C#: Cannot convert from ulong to byte

2019-07-16 14:04发布

问题:

Strange how I can do it in C++,but not in C#.

To make it clear,i'll paste the two functions in C++ and then in C# and mark the problematic lines in the C# code with a comment "//error". What the two function does is encoding the parameter and then add it in to a global variable named byte1seeds.

These are the functions in C++

//Global var:

unsigned char byte1seeds[3];

unsigned long GenerateValue( unsigned long * Ptr )
{
unsigned long val = *Ptr;
for( int i = 0; i < 32; i++ )
    val = (((((((((((val >> 2)^val) >> 2)^val) >> 1)^val) >> 1)^val) >> 1)^val)&1)|((((val&1) << 31)|(val >> 1))&0xFFFFFFFE);
return ( *Ptr = val );
}

void SetupCountByte( unsigned long seed )
{
if( seed == 0 ) seed = 0x9ABFB3B6;
unsigned long mut = seed;
unsigned long mut1 = GenerateValue( &mut );
unsigned long mut2 = GenerateValue( &mut );
unsigned long mut3 = GenerateValue( &mut );
GenerateValue( &mut );
unsigned char byte1 = (mut&0xFF)^(mut3&0xFF);
unsigned char byte2 = (mut1&0xFF)^(mut2&0xFF);
if( !byte1 ) byte1 = 1;
if( !byte2 ) byte2 = 1;
byte1seeds[0] = byte1^byte2;
byte1seeds[1] = byte2;
byte1seeds[2] = byte1;
}

Now the C# code:

I've changed the function GenerateValue.Instead of having a pointer as a parameter, it has a ulong parameter.

To call it and change both values i use:

  1. ulong mut1 = GenerateValue(mut);
  2. mut = mut1;

Here are the translated functions(the problematic lines are marked with "//error");

//Global var:
public static byte[] byte1seeds = new byte[3];

public static ulong GenerateValue(ulong val)
{
    for( int i = 0; i < 32; i++ )
        val = (((((((((((val >> 2)^val) >> 2)^val) >> 1)^val) >> 1)^val) >> 1)^val)&1)|((((val&1) << 31)|(val >> 1))&0xFFFFFFFE);
    return val ;
}

public static void SetupCountByte( uint seed )
{
    if( seed == 0 ) seed = 0x9ABFB3B6;
    ulong mut = seed;
    ulong mut1 = GenerateValue(mut);
    mut = mut1;
    ulong mut2 = GenerateValue(mut);
    mut = mut2;
    ulong mut3 = GenerateValue(mut);
    mut = mut3;
    mut = GenerateValue(mut);
    byte byte1 = (mut & 0xFF) ^ (mut3 & 0xFF); //error
    byte byte2 = (mut1 & 0xFF) ^ (mut2 & 0xFF); //error
    if( byte1 != 0 )
        byte1 = 1;
    if( byte2 != 0 )
        byte2 = 1;
    byte1seeds[0] = byte1^byte2; //error
    byte1seeds[1] = byte2;
    byte1seeds[2] = byte1;
}

The error is:

Cannot implicitly convert type 'ulong' to 'byte'. An explicit conversion exists (are you missing a cast?)

edit:the error at problematic line 3 is:

Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?)

Here comes the question: How to solve those errors?

Thanks in advance!

回答1:

Add a (byte) to cast it. As you could lose precision, you have to tell the compiler that the value will fit into a byte, i.e.

byte byte1 = (byte)((mut & 0xFF) ^ (mut3 & 0xFF));
byte byte2 = (byte)((mut1 & 0xFF) ^ (mut2 & 0xFF));


回答2:

You could loose informations. The compiler doesn't allow this kind of operations unless you explicitly tell him to do so. So try something like this:

byte result = ((byte)mut & 0xFF) ^ ((byte)mut3 & 0xFF);

This way, all variables are explicitly casted and the result will be a byte. Or you can do this:

byte result = (byte)((mut & 0xFF) ^ (mut3 & 0xFF));


回答3:

Symptom

The following code compiles in C++ but is rejected by a C# compiler, with the third line reporting type incompatibility.

ulong mut = 5;
ulong mut3 = 6;
byte foo = (mut & 0xFF) ^ (mut3 & 0xFF);

Explanation

The expression (mut & 0xFF) ^ (mut3 & 0xFF) is of type ulong and cannot be assigned to a variable of type byte.

The variable mut is a ulong. All overloads of & require operand type symmetry, so in the expression (mut & 0xFF), the value 0xFF is promoted to ulong, and the result of the operation has the type ulong.

While a similar process does also give the second subexpression the type ulong, this is incidental because in the larger expression A ^ B, the fact that expression A has the type ulong would cause expression B to be promoted.

Thus, the expression (mut & 0xFF) ^ (mut3 & 0xFF) is of type ulong and requires an explicit cast before it can be assigned to a variable of type byte.

Solution

Explicitly typecast the entire expression prior to assignment.

Remarks

People turn off warnings instead of thinking about them because most C+ libraries are riddled with defects. If you switch warnings back on you get so many it's useless trying to wade through them, even though somewhere in the mess there'll be a note to the effect of "a potentially lossy implicit typecast was required".

If you read the C# language specification, with particular regard to operators, you will learn a great many useful things. For example, this code will fail:

byte b = 0xF0 | 0x0E; //b should contain 0xFE

but these will succeed:

byte b1 = (byte)(0xF0 | 0x0E); //typecast fixes it
byte b2 = 0xF0;
b2 |= 0x0E; //reflexive operator typed by target variable


回答4:

"explicit conversion exists" indicates that you need to do an explicit cast. In this case that would be something like:

byte byte1 = (byte) ( (mut & 0xFF) ^ (mut3 & 0xFF) );
byte byte2 = (byte) ( (mut1 & 0xFF) ^ (mut2 & 0xFF) );


回答5:

There's a MSDN Knowledge Base article that explains in depth the need for the explicit downcast. The words "explicit conversion exists" in the error message are intended to be the clue that you must explicitly convert the data type by using a cast. In your specific case, that would look like this:

byte byte1 = (byte) ( (mut & 0xFF) ^ (mut3 & 0xFF) );