Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitwise AND between c_short and hex value 0x8000 causes range error due to unexpected interpretation of the most-significant bit #22716

Open
rullo24 opened this issue Feb 2, 2025 · 3 comments
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@rullo24
Copy link

rullo24 commented Feb 2, 2025

Zig Version

0.14.0-dev.850+ddcb7b1c1

Steps to Reproduce and Observed Behavior

When returning the bitwise AND between a c_short and a hex value, the most-significant bit is considered out-of-range, despite still being within the bounds of a c_short (u16). As seen in the error message below, this is because I presume the 0x8000 is being converted to the i16 equivalent and then being pushed through bitwise operations (-32767 <= i16 <= 32767).

For example (where _getCurrKeyState(virt_key) returns a c_short):

// checking if a key is currently activated
pub fn isPressed(virt_key: VK) bool {
    return ((_getCurrKeyState(virt_key) & 0x8000) != 0); // key pressed (down)
}

Error Message:

PS F:\Coding\01.Projects\06.Zig\01-Zeys\example\zig-out\bin> zig build
install
└─ install key_press
   └─ zig build-exe key_press Debug native 1 errors
F:\Coding\01.Projects\06.Zig\01-Zeys\src\zeys.zig:78:43: error: type 'c_short' cannot represent integer value '32768'
    return ((_getCurrKeyState(virt_key) & 0x8000) != 0); // key pressed (down)
                                          ^~~~~~
referenced by:
    waitUntilKeyPressed: F:\Coding\01.Projects\06.Zig\01-Zeys\src\zeys.zig:71:21
    main: F:\Coding\01.Projects\06.Zig\01-Zeys\example\src\key_press.zig:13:29
    WinStartup: C:\Program Files\zig\lib\std\start.zig:616:37
    comptime_0: C:\Program Files\zig\lib\std\start.zig:65:21
error: the following command failed with 1 compilation errors:
C:\Program Files\zig\zig.exe build-exe -freference-trace=10 -luser32 -ODebug --dep zeys -Mroot=F:\Coding\01.Projects\06.Zig\01-Zeys\example\src\key_press.zig -Mzeys=F:\Coding\01.Projects\06.Zig\01-Zeys\src\zeys.zig --cache-dir F:\Coding\01.Projects\06.Zig\01-Zeys\example\.zig-cache --global-cache-dir C:\Users\conno\AppData\Local\zig --name key_press --zig-lib-dir C:\Program Files\zig\lib\ --listen=-
Build Summary: 2/5 steps succeeded; 1 failed
install transitive failure
└─ install key_press transitive failure
   └─ zig build-exe key_press Debug native 1 errors
error: the following build command failed with exit code 1:
F:\Coding\01.Projects\06.Zig\01-Zeys\example\.zig-cache\o\41affe15a6c2524836c8c2bacba0da2e\build.exe C:\Program Files\zig\zig.exe C:\Program Files\zig\lib F:\Coding\01.Projects\06.Zig\01-Zeys\example F:\Coding\01.Projects\06.Zig\01-Zeys\example\.zig-cache C:\Users\conno\AppData\Local\zig --seed 0x3d38602b -Z355eda3502fcbc06

Expected Behavior

The most-significant bit of a c_short should still be considered within range when bitwise AND operations are taken against it.

@rullo24 rullo24 added the bug Observed behavior contradicts documented or intended behavior label Feb 2, 2025
@rullo24
Copy link
Author

rullo24 commented Feb 2, 2025

For further context, here is the implementation of the functions that are involved within the example:

// gets the state bitmap of a specified virtual key --> used to check if key as pressed down
fn _getCurrKeyState(virt_key: VK) c_short {
    const virt_key_c_short: c_short = @intFromEnum(virt_key); // converting enum val so that it is usable
    const virt_key_int: c_int = virt_key_c_short; // converting to c_int for ABI compatibility
    const key_state_short: c_short = GetAsyncKeyState(virt_key_int);
    return key_state_short;
}

@dreilly1982
Copy link
Contributor

This is because c_short is an i16, and 0x8000 as a literal is being read as a u16. Try using c_ushort instead of c_short, and see if that works better.

@rohlem
Copy link
Contributor

rohlem commented Feb 2, 2025

& currently requires both argument to be of the same type.
If you want the bit sequence that c_ushort uses for the integer value 0x8000 to be interpreted as a c_short,
you can achieve this by casting: @as(c_short, @bitCast( @as(c_ushort, 0x8000) ))

Alternatively you could also reinterpret the other argument as c_ushort: @as(c_ushort, @bitCast(_getCurrKeyState(virt_key))) & 0x8000
or directly return a c_ushort from _getCurrKeyState.
(Or use a more bespoke type, like a packed struct(u16), to address bits individually instead of using bit operations on the values directly.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

3 participants