uint32_t value = 42; /* Exactly 32 bits, unsigned */
int32_t signed_val = -5; /* Exactly 32 bits, signed */
uint8_t byte = 0xFF; /* Exactly 8 bits, unsigned */
```
| Type | Width | Range |
|------|-------|-------|
| `uint32_t` | 32 bits | 0 to 4,294,967,295 |
| `int32_t` | 32 bits | -2,147,483,648 to 2,147,483,647 |
| `uint8_t` | 8 bits | 0 to 255 |
Always use fixed-width types for predictable behavior!
---
## Bitwise Operators in C
| Operator | Name | Example | Result |
|----------|------|---------|--------|
| `~` | NOT | `~0x0F` | `0xFFFFFFF0` |
| `&` | AND | `0xCA & 0xF0` | `0xC0` |
| `\|` | OR | `0xCA \| 0x0F` | `0xCF` |
| `^` | XOR | `0xCA ^ 0xFF` | `0x35` |
```c
uint32_t a = 0xCA; /* 1100 1010 */
uint32_t b = 0xF0; /* 1111 0000 */
uint32_t and_ab = a & b; /* 0xC0 */
uint32_t or_ab = a | b; /* 0xFA */
uint32_t xor_ab = a ^ b; /* 0x3A */
```
---
## Precedence Gotcha
```c
/* BUG: evaluates as flags & (0x10 != 0) */
if (flags & 0x10 != 0) { ... }
/* CORRECT: use parentheses */
if ((flags & 0x10) != 0) { ... }
```
| Precedence | Operators |
|------------|-----------|
| Highest | `*`, `/`, `+`, `-` |
| | `<<`, `>>` |
| | `<`, `>`, `==`, `!=` |
| | `&`, `^`, `\|` |
| Lowest | `&&`, `\|\|` |
Rule: Always parenthesize bitwise ops in conditions!
---
## Shift Operators in C
**Left shift** (`<<`): Fill with 0s, multiply by 2ⁿ
```c
uint32_t x = 1;
x << 4; /* = 16 (0x10) */
```
**Right shift** (`>>`): Depends on signedness
```c
uint32_t u = 0x80;
u >> 4; /* = 0x08 (logical shift, fill with 0) */
int32_t s = -16;
s >> 2; /* Usually -4 (arithmetic shift) */
/* But implementation-defined! */
```
---
## NTLang Shift Operators
| NTLang | Token | C Implementation |
|--------|-------|------------------|
| `<<` | `TK_LSL` | `left << right` |
| `>>` | `TK_LSR` | `left >> right` (unsigned) |
| `>-` | `TK_ASR` | `(uint32_t)(((int32_t)left) >> right)` |
```c
case OP_ASR:
result = (uint32_t)(((int32_t)left) >> right);
break;
```
Cast to int32_t for ASR, back to uint32_t for storage.
---
## String-to-Integer: Base Detection
```c
uint32_t conv_str_to_uint32(char *str) {
int base = 10;
int start = 0;
if (str[0] == '0' && str[1] == 'b') {
base = 2; start = 2; /* "0b1010" */
} else if (str[0] == '0' && str[1] == 'x') {
base = 16; start = 2; /* "0xFF" */
}
/* ... */
}
```
---
## String-to-Integer: Conversion
```c
/* Process digits right-to-left */
uint32_t value = 0;
uint32_t place = 1;
int len = strlen(str);
for (int i = len - 1; i >= start; i--) {
int digit;
char c = tolower(str[i]);
if (c >= '0' && c <= '9')
digit = c - '0';
else if (c >= 'a' && c <= 'f')
digit = c - 'a' + 10;
else
exit(-1);
value += digit * place;
place *= base;
}
return value;
```
---
## Integer-to-String: Decimal
```c
void conv_uint32_to_decstr(uint32_t value, char *str) {
char temp[32];
int i = 0;
if (value == 0) {
str[0] = '0'; str[1] = '\0'; return;
}
while (value > 0) {
temp[i] = '0' + (value % 10);
value /= 10;
i++;
}
/* Reverse into output */
int len = i;
for (int j = 0; j < len; j++)
str[j] = temp[len - 1 - j];
str[len] = '\0';
}
```
---
## Integer-to-String: Hex
```c
void conv_uint32_to_hexstr(uint32_t value, char *str) {
char temp[32];
char hex_digits[] = "0123456789ABCDEF";
int i = 0;
str[0] = '0'; str[1] = 'x';
if (value == 0) {
str[2] = '0'; str[3] = '\0'; return;
}
while (value > 0) {
temp[i] = hex_digits[value % 16];
value /= 16;
i++;
}
/* Reverse into str+2 ... */
}
```
---
## Width Mask
```c
uint32_t conv_width_mask(int width) {
if (width == 32)
return 0xFFFFFFFF; /* 1 << 32 is undefined! */
return (1 << width) - 1;
}
```
| Width | Mask |
|-------|------|
| 4 | `0x0F` |
| 8 | `0xFF` |
| 16 | `0xFFFF` |
| 32 | `0xFFFFFFFF` |
```c
uint32_t masked = value & conv_width_mask(width);
```
---
## Sign Extension
```c
/* Check MSB of width-bit value */
int msb = width - 1;
if ((value >> msb) & 1) {
/* Sign extend: set upper bits to 1 */
for (int i = width; i < 32; i++) {
value |= (1 << i);
}
}
```
```text
Width 4, value = 0xB (1011):
Before: 0000 0000 ... 0000 1011
After: 1111 1111 ... 1111 1011 = -5
```
---
## Signed Output
```c
void conv_print_signed(uint32_t value,
int width, int base) {
uint32_t mask = conv_width_mask(width);
value = value & mask;
char str[64];
int msb = width - 1;
if ((value >> msb) & 1) {
/* Negative: sign-extend then negate */
for (int i = width; i < 32; i++)
value |= (1 << i);
uint32_t positive = -value;
conv_uint32_to_str(positive, str, base);
printf("-%s", str);
} else {
conv_uint32_to_str(value, str, base);
printf("%s", str);
}
}
```
---
## NTLang Output Flags
| Flag | Meaning | Example |
|------|---------|---------|
| `-b 2` | Binary output | `0b1010` |
| `-b 10` | Decimal (default) | `10` |
| `-b 16` | Hex output | `0xA` |
| `-w N` | Width in bits | (affects masking) |
| `-u` | Unsigned | `4294967286` |
```c
if (unsigned_flag) {
conv_uint32_to_str(result, str, base);
printf("%s\n", str);
} else {
conv_print_signed(result, width, base);
printf("\n");
}
```
---
## Key Patterns
| Pattern | Purpose |
|---------|---------|
| `uint32_t` / `int32_t` | Fixed-width types |
| `(value >> bit) & 1` | Test single bit |
| `value & mask` | Extract lower bits |
| `value \| (1 << i)` | Set a bit |
| `(int32_t)value >> n` | Arithmetic shift |
| `value % base` | Extract digit |
| `value / base` | Remove digit |
---
## Summary
1. **``** — Fixed-width types for portable code
2. **Bitwise ops** — `~`, `&`, `|`, `^` (watch precedence!)
3. **Shifts** — `<<` always logical, `>>` depends on signedness
4. **String ↔ Integer** — char arithmetic + place values
5. **Width mask** — `(1 << w) - 1`, special case for 32
6. **Signed output** — MSB check → sign extend → negate → print