Page 1 of 1
Long bug when negative bit is set
Posted: Sat Jan 24, 2026 6:49 pm
by infratec
Code: Select all
Procedure.l Endian(val.l)
ProcedureReturn ((val & $000000FF) << 24) | ((val & $0000FF00) << 8) | ((val & $00FF0000) >> 8) | ((val & $FF000000) >> 24)
EndProcedure
Procedure.l EndianFix(val.l)
Protected Result.q
Result = ((val & $000000FF) << 24) | ((val & $0000FF00) << 8) | ((val & $00FF0000) >> 8) | ((val & $FF000000) >> 24)
ProcedureReturn Result
EndProcedure
Define Test.l
Test = $12345678
Debug Hex(Test, #PB_Long)
Test = Endian(Test)
Debug Hex(Test, #PB_Long)
Debug ""
Test = $87654321
Debug Hex(Test, #PB_Long)
Test = Endian(Test)
Debug Hex(Test, #PB_Long)
Debug ""
Test = $87654321
Debug Hex(Test, #PB_Long)
Test = EndianFix(Test)
Debug Hex(Test, #PB_Long)
Results in:
12345678
78563412
87654321
FFFFFF87
87654321
21436587
PB 6.30 x86 on WIndows 10 x64 assembler and c backend.
I can not provide a fix for .q because there is no larger variable type then .q

Re: Long bug when negative bit is set
Posted: Sat Jan 24, 2026 6:57 pm
by skywalk
Ouch!
Any idea when this started?
Was this ok before v630 Final?
Re: Long bug when negative bit is set
Posted: Sat Jan 24, 2026 7:01 pm
by infratec
Ok, found an other way to fix:
Code: Select all
Procedure.l Endian(val.l)
ProcedureReturn ((val & $000000FF) << 24) | ((val & $0000FF00) << 8) | ((val & $00FF0000) >> 8) | ((val & $FF000000) >> 24)
EndProcedure
Procedure.l EndianFix(val.l)
Protected Result.q
Result = ((val & $000000FF) << 24) | ((val & $0000FF00) << 8) | ((val & $00FF0000) >> 8) | ((val & $FF000000) >> 24)
ProcedureReturn Result
EndProcedure
Procedure.l Endian2(val.l)
ProcedureReturn $FF & val >> 24 | ($FF & val) << 24 | ($FF & val >> 16) << 8 | ($FF & val >> 8) << 16
EndProcedure
Define Test.l
Test = $12345678
Debug Hex(Test, #PB_Long)
Test = Endian(Test)
Debug Hex(Test, #PB_Long)
Debug ""
Test = $87654321
Debug Hex(Test, #PB_Long)
Test = Endian(Test)
Debug Hex(Test, #PB_Long)
Debug ""
Test = $87654321
Debug Hex(Test, #PB_Long)
Test = EndianFix(Test)
Debug Hex(Test, #PB_Long)
Debug ""
Test = $87654321
Debug Hex(Test, #PB_Long)
Test = Endian2(Test)
Debug Hex(Test, #PB_Long)
But I still think the first version should work too.
I can not always think about compiler internal conversion stuff.

Re: Long bug when negative bit is set
Posted: Sat Jan 24, 2026 7:11 pm
by infratec
I don't know if this happens in older versions too, but I think so.
Re: Long bug when negative bit is set
Posted: Sat Jan 24, 2026 8:08 pm
by skywalk
Thanks, I'll keep looking but turns out I only had to use byte swapping for word data coming from an instrument.
Code: Select all
; ; Type, Bytes, Min, Max, C Type
w.w[0] ; Word, 2, -32768, 32767, short
Like you, I prefer to rely on basic compiler operation to be confirmed by Purebasic unit testing prior to beta release.
Fred - Is there a separate thread for suggestions on UNIT tests for Purebasic/Spiderbasic?
I remember you mentioned BUG reports get added to UNIT tests, but maybe we can request tests added even if not a BUG?
Re: Long bug when negative bit is set
Posted: Sat Jan 24, 2026 8:48 pm
by freak
This is fully correct. No bug.
PB uses arithmetic shift, as mentioned in the documentation:
https://www.purebasic.com/documentation ... ables.html
More details:
https://en.wikipedia.org/wiki/Arithmetic_shift
If you want to avoid repeating the sign bit with a shift right, mask out the bits AFTER shifting:
Code: Select all
Procedure.l Endian(val.l)
ProcedureReturn ((val & $000000FF) << 24) | ((val & $0000FF00) << 8) | ((val & $00FF0000) >> 8) | ((val >> 24) & $000000FF)
EndProcedure
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 11:42 am
by SMaag
As freak said, It's by design not a bug. It's the PB arithmtic shift. That's often a problem!
You have to mask out the the upper Bits after the shift.
But here is a full solution for the BSWAP
Code: Select all
Procedure.q BSWAP64(value.q)
CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
CompilerIf #PB_Compiler_32Bit
!lea ecx, [p.v_value] ; load effective address of value (:= @value)
!mov edx, dword [ecx]
!mov eax, dword [ecx +4]
!bswap edx
!bswap eax
ProcedureReturn ; 64Bit Return use EAX and EDX Register
CompilerElse
!mov rax, qword [p.v_value]
!bswap rax
ProcedureReturn
CompilerEndIf
CompilerElse ; C-Backend
!return __builtin_bswap64(v_value);
CompilerEndIf
EndProcedure
Structure pSwap ; Pointer Structure for swapping
a.a[0] ; unsigned Byte-Value
u.u[0] ; unsigned WORD-Value
EndStructure
Procedure.q BSWAP64_PB(value.q)
Protected *Swap.pSwap
*Swap = @value
Swap *Swap\a[0], *Swap\a[7]
Swap *Swap\a[1], *Swap\a[6]
Swap *Swap\a[2], *Swap\a[5]
Swap *Swap\a[3], *Swap\a[4]
ProcedureReturn value
EndProcedure
Test = $8877665544332211
Debug Hex(Test, #PB_Quad)
Debug Hex(BSWAP64(Test), #PB_Quad)
Debug Hex(BSWAP64_PB(Test), #PB_Quad)
If you need more Bit-Functions! I solved nearly all that Bit-Stuff for industrial use:
https://github.com/Maagic7/PureBasicFra ... ule_Bit.pb
And here the Macro verison for an universal BSWAP. But there is a problem in C-Backend, because C-Backend needs all
variables in LoCase.
Code: Select all
;{ TODO: Solve the LoCase var problem in C-Backend
;}
; ===========================================================================
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
; there is a problem in C-Backend. In C-Backend we have to
; call BSwapVar always with variable name in lower case
; if we define L.l and call BSwapVar(L) we get an error
; if we call BSwapVar(l) it works!
; it looks like the compiler LoCase all variables but in a Macro not!
CompilerWarning "Use of Macro BSwapVar(var) in C-Backend: Attention! Pass all variable names in LoCase : BSwapVar(myvar)! BSwapVar(MyVar) produce an Error!"
Macro BSwapVar(var)
CompilerSelect SizeOf(var)
CompilerCase 2
!v_#var = __builtin_bswap16(v_#var);
CompilerCase 4
!v_#var = __builtin_bswap32(v_#var);
CompilerCase 8
!v_#var = __builtin_bswap64(v_#var);
CompilerEndSelect
EndMacro
CompilerElse ; ASM-Backend
; We use the EnableASM command only to load and save the variable
; because if we pass directly the 'MOV EAX, var' we have to add v_ for standard code
; or p.v_ for variables in a procedure. With the PB buildin ASM it is done by PB.
Macro BSwapVar(var)
EnableASM
CompilerSelect SizeOf(var)
CompilerCase 2
!XOR EAX, EAX
MOV AX, var
!XCHG AL, AH
MOV var, AX
CompilerCase 4
MOV EAX, var
!BSWAP EAX
MOV var, EAX
CompilerCase 8 ; Quad
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
MOV RAX, var
!BSWAP RAX
MOV var, RAX
CompilerElse ; ASM x32
LEA ECX, var ; load effective address of var : ECX= @var
!MOV EDX, DWORD [ECX]
!MOV EAX, DWORD [ECX +4]
!BSWAP EDX
!BSWAP EAX
!MOV DWORD [ECX], EAX
!MOV DWORD [ECX +4], EDX
CompilerEndIf
CompilerEndSelect
DisableASM
EndMacro
CompilerEndIf
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 2:52 pm
by Michael Vogel
We have to deal with such things here and then - especially when we try to be extra clever...
...therefore it doesn't hurt (me) very often but then very hard.
One example I had a while ago, the following code was used as a custom callback for a drawing routine. I thought I did a good job to get a fast code:
Code: Select all
#DrawOpaque=$FF000000
Procedure LedMerge(x,y,s,d)
x=d&#DrawOpaque
If x>s
ProcedureReturn x|Calc\ColorTxt
Else
ProcedureReturn (s&#DrawOpaque)|Calc\ColorTxt
EndIf
EndProcedure
Until PB 6 everything the routine above worked fine (32/64) but with PB 6 I've had to change the header line to
Procedure.l LedMerge(x,y,s.l,d.l). I was sure everything will still work fine, but the resulting graphic output was wrong.
So I needed to rearrange everything just a little bit (which took a while to do it anyhow):
Code: Select all
Procedure.l LedMerge(x,y,s.l,d.l)
x=d&#DrawOpaque
y=s&#DrawOpaque
If x>y
ProcedureReturn x|Calc\ColorTxt
Else
ProcedureReturn y|Calc\ColorTxt
EndIf
EndProcedure
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 3:15 pm
by skywalk
Yes, that's why I suggested unit tests or assert myimportantmath == 42;.
Same here, not big burns, but an ouch nonetheless that should be avoided.
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 6:03 pm
by Little John
skywalk wrote: Sun Jan 25, 2026 3:15 pm
Yes, that's why I suggested unit tests or assert myimportantmath == 42;.
We already have
Assert() in PureBasic.
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 7:57 pm
by #NULL
For unit testing (including Assert) there is pb_folder/sdk/pureunit/
But maybe Skywalk was talking about suggestions for specific tests that should be integrated into pb(?)
Re: Long bug when negative bit is set
Posted: Sun Jan 25, 2026 8:08 pm
by skywalk
Are the PB release unit tests published?
Like, nested parenthesis booleans, float and integer math.
Threaded variable destruction.
Race condition foot fall.
Memory leak checkers.
I know SQLite has some hidden and some published.