Why xor operation on constants (symbol) works differently when variables are used in their place

Take a look at the following code:

Case 1:

char a = 'x' ^ 'y';

      

It works fine. But when I use variable instead of constants like here:

Case 2:

char x = 'x';
char y = 'y';
char a = x ^ y; // Error!

      

In java language: case 1 works and the value of a is 1, but case 2 does not work.

In C and C ++: both cases work and the value of a is 1

In C #: both cases don't work.

In javascript: both cases work, which is not an HLL, and the value of a turns out to be 0.


I understand that java converts variables to integer to perform a binary operation, but why does it work in case 1 and not in case 2, why doesn't it work in C #. And why the values ​​in javascript are different.

Update When I made the variables final than it works in java but still not in C #

final char x = 'x';
final char y = 'y';
char a = x ^ y;

      

But still I can't figure out why constants work, but when using a variable, they are not. And why doesn't the same thing happen with another high-level programming language.
I think this is a basic operation and should work in all programming languages ​​with the same behavior.

Note To test all of the above cases in javascript, I replace "char" with "var" in all cases and they work.

+3


source to share


3 answers


The answer is Java only.

Expression 'x' ^ 'y'

is a constant expression ; x ^ y

not if both variables are not declared final

. In addition, the result is int

; ^

is an integral bitwise operator , which means that both operands must be promoted to integral type before being evaluated. char

advancing to int

.

So you have this expression int

, and you are trying to narrow it down to char

. In general, this can lead to a loss of precision (ints - 4 bytes, characters - 2), so the compiler won't let you do this unless you explicitly indicate what you want to do (by clicking on char

). However, you can implicitly narrow down constant expressions if their value will fit into the new type. From JLS 5.2 :



  • A narrowing primitive conversion can be used if the type of the variable is byte

    , short

    or char

    , and the value of the constant expression is represented in the type of the variable .

(emphasis added)

Intuitively, it makes sense: the mistake is to tell you that you might lose precision, and therefore it wants you to confirm that you know it; in a sense, this is a loud warning. But if the compiler can know for sure that this will not happen, as it can for a constant expression, then this will make it easier for you and "hide" this warning.

+5


source


I will review the C languages ​​which are C, C ++ and C #.

There is no implicit conversion from integral type to char type in C #. According to section "11.1.5" Integral Types "of ECMA 334" C # Specification "

β€’ There are no implicit conversions from other types to char. In particular, although sbyte, byte, and ushort have ranges of values ​​that are fully represented using char, there are no implicit conversions from sbyte, byte, or ushort to char.

So, you need to explicitly specify the result of the operator to input char. for example

using System;

namespace ExclusiveOr
{
    class Program
    {
        static void Main(string[] args)
        {
            char a = ( char )('x' ^ 'y' );
            char c = 'x', d = 'y';
            char b = ( char )( c ^ d );

            Console.WriteLine("a = {0}, b = {1}", (int)a, (int)b);
        }
    }
}

      

Output signal

a = 1, b = 1

      

In accordance with the C standard (section 6.7.9 "Initialization")

4 All expressions in an initializer for an object that has static or stream storage duration must be constant expressions or literal strings

So for example, this code will compile

#include <stdio.h>

char a = 'x' ^ 'y';

int main(void) 
{
    printf( "a = %d\n", a );

    return 0;
}

      



Output signal

a = 1

      

However, this code will not compile

#include <stdio.h>

char c = 'x';
char d = 'y';

char b = c ^ d;

int main(void) 
{
    printf( "b = %d\n", b );

    return 0;
}

      

will not compile. The GCC compiler will throw an error

prog.c: 8: 1: error: initialization element is not a constant char b = c ^ d;

However, if you make varaible b local then the code will compile successfully

#include <stdio.h>

char c = 'x';
char d = 'y';


int main(void) 
{
    char b = c ^ d;
    printf( "b = %d\n", b );

    return 0;
}

      

Output signal

b = 1

      

There is no such limitation in C ++ for objects with static storage duration, so all sample programs like the C programs shown above will compile.

+1


source


Under normal circumstances, the operands of the following binary operators are "expanded" before performing the operation.

(From JLS 5.6.1 )

  • Multiplicative operators *, / and% (Β§15.17)

  • Addition and Subtraction Operators for Numeric Types + and - (Β§15.18.2)

  • Numerical comparison operators <, <=,>, &> = (Β§15.20.1)

  • Numerical equality operators == and! = (Β§15.21.1)

  • The bitwise integer operators &, ^ and | (Β§15.22.1)

  • In some cases, the conditional operator ?: (Β§15.25)

In the case of operands, the char

extension will convert the operands to int

.

For arithmetic and bitwise operations, the result type of the operation is the same as the "wider" of the two operands.

When x

and y

are of a type char

, the expression x ^ y

gives you the value int

. This cannot be assigned back char

without a set of types, and hence you will get a compilation error.


In the case where you use literals char

, the same expansion process occurs. But the language has a "special exception" that allows you to implicitly narrow the meaning of a constant expression, provided that the value of the constant expression will fit into the type. In this case, 'x' ^ 'y'

will "fit" into char

, so assignment is allowed.

JLS reference for this exception for JLS 5.2 constant expressions .

0


source







All Articles