Not on Cardinal lazarus / 64-FPC development ---------------------------------------------------------------------- Okoba · 2023-10-11 07:53 Hi, I have this code and I get the warnings, and I want to ask how FPC bitwise operation works? I get why V1 may be a problem. It is a const, FPC assumes Integer, and not makes it a negative, not fitting in V1, a Cardinal. But why V2 warns me? I clearly say that cast C to Cardinal, so not of it, should still be Cardinal, am I wrong? For V1, V2 and V3, all result the same value, but the warn is puzzling. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  C = 2;var  V0, V1, V2, V3: Cardinal;begin  V0 := C;  V1 := not C; //Warning: Range check error while evaluating constants (-3 must be between 0 and 4294967295)  V2 := not Cardinal(C); //Warning: Range check error while evaluating constants (-3 must be between 0 and 4294967295)  V3 := Cardinal(not C);   WriteLn(V0); //2  WriteLn(V1); //4294967293  WriteLn(V2); //4294967293  WriteLn(V3); //4294967293 ---------------------------------------------------------------------- Zvoni · 2023-10-11 08:26 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  C = Cardinal(2);No warnings. btw: With your code i only get a Warning for V1, not V2, so no idea. Might be your FPC-version Mine: FPC3.2.2-32Bit ---------------------------------------------------------------------- Okoba · 2023-10-11 08:32 For me it warns me in 3.2.2 and 3.3.1, Windows and 64bit. Declaring the const as Cardinal wont help and the warn persists. In your case, maybe Lazarus setting is on filtering those messages. For me, it is on off, so all messages are shown. ---------------------------------------------------------------------- TRon · 2023-10-11 08:45 Quote from: Okoba on October 11, 2023, 09:53:48 amI have this code and I get the warnings, and I want to ask how FPC bitwise operation works? It has nothing to do with bitwise operations rather with the fact that a compiler default to using a single type to convert to in order to operate on values. It is written in the manual that can be found online. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  C = 2;var  V0, V1, V2, V3: Cardinal;begin  V0 := C;   V1 := not C; //C is constant get 'converted' by the compiler to integer, which is signed, then negated (to integer) trying to stuff that into a cardinal again. The compiler is correct to complain.  V1 := cardinal(not C);   V2 := not Cardinal(C); //C is cast to cardinal get 'converted' by the compiler to integer, then that result is negated (to integer) and stuffed into a cardinal again. Also here the compiler is correct to complain.  V2 := cardinal(not cardinal(C);   WriteLn(V0); //2  WriteLn(V1); //4294967293  WriteLn(V2); //4294967293  WriteLn(V3); //4294967293 ---------------------------------------------------------------------- Zvoni · 2023-10-11 08:46 Quote from: Okoba on October 11, 2023, 10:32:34 amFor me it warns me in 3.2.2 and 3.3.1, Windows and 64bit. Declaring the const as Cardinal wont help and the warn persists. In your case, maybe Lazarus setting is on filtering those messages. For me, it is on off, so all messages are shown. Just tried your code again in FPC3.2.2-32Bit, with no Filter at all on messages. V1 is the only warning ---------------------------------------------------------------------- MathMan · 2023-10-11 08:47 It is not the not operation that produces the warnng, but the assignment := - that is why you see the warning for V1 and V2 but not for V3 where you hard cast to the correct target type. Seems TRon beat me with the reply ... Cheers, MathMan ---------------------------------------------------------------------- Josh · 2023-10-11 08:48 constant c=3 is shortint (-128 .. 127), notting becomes negative and cadinal is longword (0..4294967295), i would expect a rangecheck error. I suspect different definitions of types vary on Compilermode , tp, delphi, etc... https://www.freepascal.org/docs-html/ref/refsu4.html QuoteRemark The compiler decides on the type of an integer constant based on the value: An integer constant gets the smallest possible signed type. The first match in table (3.3) is used. Table 3.3: Integer constant type mapping Range   Type -128..127   Shortint 128..255   Byte -32768..32767   Smallint 32768..65535   Word -2147483648..2147483647   longint 2147483648..4294967295   Cardinal (longword) -9223372036854775808 .. 9223372036854775807   Int64 That means constants in the range -128..127 are mapped to shortint, constants in range 128..255 are mapped to byte, etc. Constants in the range 2147483647..high(cardinal) are parsed as cardinals, and all decimal constants which do not fit either of the above ranges are parsed as 64-bit integer constants. ---------------------------------------------------------------------- Okoba · 2023-10-11 08:50 I accept V1. But for V2, should we say, not always converts a value to integer? Otherwise, in case of V2, I cleary stated that I want C as Cardinal, and then I not it so I expect it to still be Cardinal! ---------------------------------------------------------------------- TRon · 2023-10-11 08:54 Quote from: Okoba on October 11, 2023, 10:50:15 amI accept V1. But for V2, should we say, not always converts a value to integer? If that makes you sleep better at night then use that explanation. It is wrong though. Again it is the compiler that does things behind the scenes for you. no matter which operation you use. QuoteOtherwise, in case of V2, I cleary stated that I want C as Cardinal, and then I not it so I expect it to still be Cardinal! No. I wrote the comments for a reason. ---------------------------------------------------------------------- Zvoni · 2023-10-11 08:57 Quote from: TRon on October 11, 2023, 10:54:55 amQuoteOtherwise, in case of V2, I cleary stated that I want C as Cardinal, and then I not it so I expect it to still be Cardinal! No. I wrote the comments for a reason. Then why don't i get a warning for V2? Went through all possible combinations in project-options, no filters on compiler-messages. I only get the one warning for V1 ---------------------------------------------------------------------- TRon · 2023-10-11 09:00 Quote from: Zvoni on October 11, 2023, 10:57:39 amThen why don't i get a warning for V2? Went through all possible combinations in project-options, no filters on compiler-messages. I only get the one warning for V1 hmz. perhaps because I'm on 64 bit (other conversion rules apply) ? Code: [Select]$> fpc -b ww.pas Free Pascal Compiler version 3.2.2 [2021/05/16] for x86_64 Copyright (c) 1993-2021 by Florian Klaempfl and others Target OS: Linux for x86-64 Compiling ww.pas ww.pas(11,9) Warning: range check error while evaluating constants (-3 must be between 0 and 4294967295) ww.pas(12,9) Warning: range check error while evaluating constants (-3 must be between 0 and 4294967295) Linking ww 18 lines compiled, 0.0 sec 2 warning(s) issued The compiler clearly states what is happening exactly. If not enough then use smaller steps to verify. ---------------------------------------------------------------------- Dzandaa · 2023-10-11 09:10 Hi, If you look at the binary value, there is nothing strange: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  C = 2;var  V0, V1, V2, V3: Cardinal;  Str, NotStr: String;begin  V0 := C;  Str := intToBin(C, 32 );  // '00000000000000000000000000000010'  NotStr := intToBin(Not C, 32); // '11111111111111111111111111111101' = 4294967293  V1 and V2 assign a negative value (-3) -> Error In the case of V3 "Not" invert the bits of C and assign the result to V3 literally. B-> ---------------------------------------------------------------------- TRon · 2023-10-11 09:12 @Zvoni: If I cross-compile to win32 then indeed the compiler only complains on the assignment of v1. Quote from: Dzandaa on October 11, 2023, 11:10:28 amIn the case of V3 "Not" invert the bits of C and assign the result to V3 literally. No. the result of that operation is converted by the compiler into a integer and tries to assign that integer to a cardinal. That will not fit and then complains. Unless using the cast to cardinal what TS is using (so that is the reason the compiler has no reason to complain). ---------------------------------------------------------------------- Okoba · 2023-10-11 09:14 @TRon, I don't get your explanation on V2. Why compiler converts a Cardinal to Integer? Because it wants to "not"? Or any math operation will convert to Integer anyway? I tried the code with QWord and correctly, only V1 warns me. So the problem rises for Cardinal, or DWord. @Dzandaa As shown in my sample code, the value is correct, the warn is my concern, because it think there is something wrong I need to take care off. ---------------------------------------------------------------------- TRon · 2023-10-11 09:20 Quote from: Okoba on October 11, 2023, 11:14:23 am@TRon, I don't get your explanation on V2. Why compiler converts a Cardinal to Integer? Because it wants to "not"? Or any math operation will convert to Integer anyway? /any/ operation with ordinal types. read the link posted by josh and try understand the native integer part. https://www.freepascal.org/docs-html/ref/refsu4.html Quote from: Okoba on October 11, 2023, 11:14:23 am@Dzandaa As shown in my sample code, the value is correct, the warn is my concern, because it think there is something wrong I need to take care off. There actually is something wrong. You try to assign a negative integer to a cardinal. that means potential information is lost. ---------------------------------------------------------------------- Okoba · 2023-10-11 11:14 I tried readying the link and the only thing I can deduct that explains the difference I see between Dword and QWord is this: QuotePlease note that the qword and int64 types are not true ordinals, so some Pascal constructs will not work with these two integer types. and there is a part saying: QuoteThe result of binary arithmetic operators (+, -, *, etc.) is determined in the following way: If at least one of the operands is larger than the native integer size, the result is chosen to be the smallest type that encompasses the ranges of the types of both operands. This means that mixing an unsigned with a smaller or equal in size signed will produce a signed type that is larger than both of them. If both operands have the same signedness, the result is the same type as them. The only exception is subtracting (-): in the case of unsigned - unsigned subtracting produces a signed result in FPC (as in Delphi, but not in TP7). Mixing signed and unsigned operands of the “native” int size produces a larger signed result. This means that mixing longint and longword on 32-bit platforms will produce an int64. Similarly, mixing byte and shortint on 8-bit platforms (AVR) will produce a smallint. So what step of this rules made it to change the Cardinal to an Integer because of not? I still do not know why not made a Cardinal (DWord) turn to an Integer, and why that reason does not effect QWord. ---------------------------------------------------------------------- Zvoni · 2023-10-11 12:03 Quote from: Okoba on October 11, 2023, 01:14:48 pmI tried readying the link and the only thing I can deduct that explains the difference I see between Dword and QWord is this: QuotePlease note that the qword and int64 types are not true ordinals, so some Pascal constructs will not work with these two integer types. and there is a part saying: QuoteThe result of binary arithmetic operators (+, -, *, etc.) is determined in the following way: If at least one of the operands is larger than the native integer size, the result is chosen to be the smallest type that encompasses the ranges of the types of both operands. This means that mixing an unsigned with a smaller or equal in size signed will produce a signed type that is larger than both of them. If both operands have the same signedness, the result is the same type as them. The only exception is subtracting (-): in the case of unsigned - unsigned subtracting produces a signed result in FPC (as in Delphi, but not in TP7). Mixing signed and unsigned operands of the “native” int size produces a larger signed result. This means that mixing longint and longword on 32-bit platforms will produce an int64. Similarly, mixing byte and shortint on 8-bit platforms (AVR) will produce a smallint. So what step of this rules made it to change the Cardinal to an Integer because of not? I still do not know why not made a Cardinal (DWord) turn to an Integer, and why that reason does not effect QWord. This is about binary arithmetic operations, not logical/Bitwise operations, so no idea why you think that has anything to do with it (except if someone can explain, that arithmetic operations can be "translated" to logical/bitwise operations) ---------------------------------------------------------------------- Okoba · 2023-10-11 13:11 I don't know too. I was just guessing. My understanding was that, if you do bitwise operation, you will always get the same type. For example, for arithmetic operation, you can get a Int64 from multiplying two Integer. But doing shr on a DWord, will always be a DWord. So why "Not" is different or I misunderstood something, is my question. ---------------------------------------------------------------------- cdbc · 2023-10-11 13:38 Hi "Not" is a negation operator, so ofc, it will try to give you the negative value, but you can't have negatives in an unsigned type like cardinal, longword, dword, qword, ptruint or for that matter byte! If the compiler was an a***, it would give anything in between 0..high(datatype) that is NOT "2" in your example, so give it credit for trying to play along with your shenanigans... Regards Benny ---------------------------------------------------------------------- Okoba · 2023-10-11 13:50 I thought "Not" makes 0 to 1, 00 to 11 and 01 to 10. Am I wrong? ---------------------------------------------------------------------- Zvoni · 2023-10-11 13:52 Quote from: cdbc on October 11, 2023, 03:38:35 pmHi "Not" is a negation operator, so ofc, it will try to give you the negative value, but you can't have negatives in an unsigned type like cardinal, longword, dword, qword, ptruint or for that matter byte! If the compiler was an a***, it would give anything in between 0..high(datatype) that is NOT "2" in your example, so give it credit for trying to play along with your shenanigans... Regards Benny You would have to explain, how a logical/bitwise operator "knows" the operand is positive/negative resp. its result a logical/bitwise operator doesn't care about signed/unsigned, it (should) only care(s) about bits ---------------------------------------------------------------------- TRon · 2023-10-12 04:51 Quote from: Okoba on October 11, 2023, 01:14:48 pmI tried readying the link and the only thing I can deduct that explains the difference I see between Dword and QWord is this: Start with the basics first. QuoteRemark The compiler decides on the type of an integer constant based on the value: An integer constant gets the smallest possible signed type. The first match in table (3.3) is used. Now first ask yourself: - what is C (typewise) ? - what is the "native" integer for your platform - So how does c get promoted/demoted ? Then apply the rest of the rules. If you still have no idea what is being talked about then you can proof it: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program proof; {$mode objfpc}{$H+} uses  math; const  c = 2; begin  writeln('c = #', c);  writeln('c = $', HexStr(c, sizeof(c) * 2));  writeln('c = %', BinStr(c, sizeof(c) * 8));  writeln('sizeof(c) = ', sizeof(c), ' bytes');  writeln('sign(c) = ', sign(c));   writeln;   writeln('cardinal(c) = #', cardinal(c));  writeln('cardinal(c) = $', HexStr(cardinal(c), sizeof(cardinal(c)) * 2));  writeln('cardinal(c) = %', BinStr(cardinal(c), sizeof(cardinal(c)) * 8));  writeln('sizeof(cardinal(c)) = ', sizeof(cardinal(c)), ' bytes');  writeln('sign(cardinal(c)) = ', sign(cardinal(c)));   writeln;   writeln('not c = #', not c);  writeln('not c = $', HexStr(not c, sizeof(not c) * 2));  writeln('not c = %', BinStr(not c, sizeof(not c) * 8));  writeln('sizeof(not c) = ', sizeof(not c), ' bytes');  writeln('sign(not c) = ', sign(not c));   writeln;   writeln('cardinal(not c) = #', cardinal(not c));  writeln('cardinal(not c) = $', HexStr(cardinal(not c), sizeof(cardinal(not c)) * 2));  writeln('cardinal(not c) = %', BinStr(cardinal(not c), sizeof(cardinal(not c)) * 8));  writeln('sizeof(cardinal(not c)) = ', sizeof(cardinal(not c)), ' bytes');  writeln('sign(cardinal(not c)) = ', sign(cardinal(not c)));end. ---------------------------------------------------------------------- TRon · 2023-10-12 05:33 Quote from: Zvoni on October 11, 2023, 02:03:59 pmThis is about binary arithmetic operations, not logical/Bitwise operations, so no idea why you think that has anything to do with it (except if someone can explain, that arithmetic operations can be "translated" to logical/bitwise operations) Yeah well... to make things simpler .. (from here) "Logical operators act on the individual bits of ordinal expressions. Logical operators require operands that are of an integer type, and produce an integer type result.". This act different from the boolean operator as there the operator expects a single bit (true/false) "Boolean operators can only have boolean type operands, and the resulting type is always boolean." So it /might/ appear that the operators act exactly the same but basically they do not. Ofc you can 'convert' a single bit to an integer or an integer to a single bit (any way you deem fit) so that you can switch between which operator is applied. I personally have not found any use for it though (*) (*) I forgot one pesky thing. C and its "if x then", which actually represents if x <> 0.