Check out the following code:
sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = sba + sbb;
byte ba, bb, bv;
ba = 1;
bb = 2;
bv = ba + bb;
short sa, sb, sv;
sa = 1;
sb = 2;
sv = sa + sb;
ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = usa + usb;
Do you think this code can be executed correctly? What will happen? The result is: there will be a compilation error in this code.
The correct code should be as follows:
sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = (sbyte)(sba + sbb);
byte ba, bb, bv;
ba = 1;
bb = 2;
bv = (byte)(ba + bb);
short sa, sb, sv;
sa = 1;
sb = 2;
sv = (short)(sa + sb);
ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = (ushort)(usa + usb);
(("{0},{1},{2},{3}", sbv, bv, sv, usv));
What is the reason for this?
In fact, the underlying CLR only supports int, int64, native int, float, and double. The underlying sbyte, byte, short, ushort, and clr are not supported. These types are represented by int at the bottom. The minimum number pushed into the CLR stack is 4 bytes, and those less than 4 bytes will be symbolically expanded according to their type or 0 will be expanded to 4 bytes int type. In this way, the result of the four operations is also int type, and finally the assignment needs to be cast. It will be clear if the compiled IL code is analyzed.
Why can the following code be compiled?
short sb;
sb=2;
sb += 1;
In fact, the final assignment in the compiled IL code also includes type conversion operations.
See a more detailed explanation:
short s=0;
s = s + 1; // Report an error, the right end is a complex expression, 1 is interpreted as int
s+=1; //No error is reported, 1 is interpreted as short, please see the explanation below
s += 32768; //Report an error, obviously 32768 cannot be interpreted as short, but can only be interpreted as int
s+=(s+1); //Report an error, the right end is a complex expression, 1 is interpreted as int
From the above one can see a rule, that is,Implicit benign type conversion in complex expression calculations can be directly interpreted or converted into 4-byte aligned CLS compatible types, such as int/long. The reason is very simple: it saves trouble and guarantees performance.(There are considerations not only when running efficiency, but also when code generation is considered, so this consideration is in one step). For example, 1 in s=s+1 is interpreted as int, not short, which is reasonable.But if it is not a complex expression, but just a simple and constant number, the compiler will not follow the "4-byte-aligned CLS compatible type" when parse, and it will automatically determine the most suitable type based on other parts.(This approach is also reasonable, because it is still in the parse stage at this time, and it is the first priority to quickly determine whether the type is compatible. Performance and misalignment are secondary issues. Therefore, there is no need to explain the type of numeric constants in one step at this time. Just follow the fastest and most trouble-free principle...) For example, the two examples of s+=1 and s+=32768, the former 1 is interpreted as short, so it is legal, and the latter 32768 will be forced to interpret as int, and the left and right types are incompatible, so an error occurs. Similarly, the above explanation also applies to the example of s+=(s+1): (s+1) is a complex expression, not a simple numeric constant, so it is interpreted as (int)s+(int)1, rather than (short)s+(short)1, thereby reporting an error.
Please note that the above explanation is mainly aimed at the parse stage. In fact, when the code generation stage is reached, the type may be further improved for performance purposes, such as the example of s+=1. In fact, in the IL code generation stage, the (short)1 identified in this parse stage is eventually promoted to (int)1. This should be the 4-byte alignment of IL parameters observed by Rick.In fact, to avoid confusion, I think it is enough for ordinary users to understand the parser level, because type discrimination and compatibility checking are no longer a key issue in the code generation stage., but of course, as long as it is a benign type improvement, it can be done at any stage. Even as long as the compiler has obtained the correct type information in the parse stage, then non-benign type conversion of variables is performed in the code generation stage, which is also a guaranteed design behavior. At this point, I believe the explanation should be complete...
Copy the codeThe code is as follows:
sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = sba + sbb;
byte ba, bb, bv;
ba = 1;
bb = 2;
bv = ba + bb;
short sa, sb, sv;
sa = 1;
sb = 2;
sv = sa + sb;
ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = usa + usb;
Do you think this code can be executed correctly? What will happen? The result is: there will be a compilation error in this code.
The correct code should be as follows:
Copy the codeThe code is as follows:
sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = (sbyte)(sba + sbb);
byte ba, bb, bv;
ba = 1;
bb = 2;
bv = (byte)(ba + bb);
short sa, sb, sv;
sa = 1;
sb = 2;
sv = (short)(sa + sb);
ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = (ushort)(usa + usb);
(("{0},{1},{2},{3}", sbv, bv, sv, usv));
What is the reason for this?
In fact, the underlying CLR only supports int, int64, native int, float, and double. The underlying sbyte, byte, short, ushort, and clr are not supported. These types are represented by int at the bottom. The minimum number pushed into the CLR stack is 4 bytes, and those less than 4 bytes will be symbolically expanded according to their type or 0 will be expanded to 4 bytes int type. In this way, the result of the four operations is also int type, and finally the assignment needs to be cast. It will be clear if the compiled IL code is analyzed.
Why can the following code be compiled?
Copy the codeThe code is as follows:
short sb;
sb=2;
sb += 1;
In fact, the final assignment in the compiled IL code also includes type conversion operations.
See a more detailed explanation:
Copy the codeThe code is as follows:
short s=0;
s = s + 1; // Report an error, the right end is a complex expression, 1 is interpreted as int
s+=1; //No error is reported, 1 is interpreted as short, please see the explanation below
s += 32768; //Report an error, obviously 32768 cannot be interpreted as short, but can only be interpreted as int
s+=(s+1); //Report an error, the right end is a complex expression, 1 is interpreted as int
From the above one can see a rule, that is,Implicit benign type conversion in complex expression calculations can be directly interpreted or converted into 4-byte aligned CLS compatible types, such as int/long. The reason is very simple: it saves trouble and guarantees performance.(There are considerations not only when running efficiency, but also when code generation is considered, so this consideration is in one step). For example, 1 in s=s+1 is interpreted as int, not short, which is reasonable.But if it is not a complex expression, but just a simple and constant number, the compiler will not follow the "4-byte-aligned CLS compatible type" when parse, and it will automatically determine the most suitable type based on other parts.(This approach is also reasonable, because it is still in the parse stage at this time, and it is the first priority to quickly determine whether the type is compatible. Performance and misalignment are secondary issues. Therefore, there is no need to explain the type of numeric constants in one step at this time. Just follow the fastest and most trouble-free principle...) For example, the two examples of s+=1 and s+=32768, the former 1 is interpreted as short, so it is legal, and the latter 32768 will be forced to interpret as int, and the left and right types are incompatible, so an error occurs. Similarly, the above explanation also applies to the example of s+=(s+1): (s+1) is a complex expression, not a simple numeric constant, so it is interpreted as (int)s+(int)1, rather than (short)s+(short)1, thereby reporting an error.
Please note that the above explanation is mainly aimed at the parse stage. In fact, when the code generation stage is reached, the type may be further improved for performance purposes, such as the example of s+=1. In fact, in the IL code generation stage, the (short)1 identified in this parse stage is eventually promoted to (int)1. This should be the 4-byte alignment of IL parameters observed by Rick.In fact, to avoid confusion, I think it is enough for ordinary users to understand the parser level, because type discrimination and compatibility checking are no longer a key issue in the code generation stage., but of course, as long as it is a benign type improvement, it can be done at any stage. Even as long as the compiler has obtained the correct type information in the parse stage, then non-benign type conversion of variables is performed in the code generation stage, which is also a guaranteed design behavior. At this point, I believe the explanation should be complete...