Converting a few lines of pure C code to AL

In this video, I tackle the task of re-creating a C-based hash function in AL. Check it out:

https://youtu.be/eUgRPh9w_3c

In this video, Erik walks through the surprisingly tricky process of converting a simple 5-line C hash function (FNV hash) into AL for Business Central. What sounds straightforward quickly becomes an exercise in dealing with AL’s limitations around unsigned integers, hexadecimal constants, and bitwise operations.

The Challenge: FNV Hash in C

For an upcoming version of the Simple Optic Designer, Erik needed to calculate an FNV (Fowler–Noll–Vo) hash — a hash function that isn’t supported by the BC Data Encryption codeunit. Looking up the algorithm, he found a clean C implementation that’s essentially just five lines of code:

The C function takes a string and a length, then loops through all characters. It maintains a running hash value, multiplies it by a prime number (expressed in hex), and performs a bitwise XOR operation with each character’s byte value. Simple enough in C — but translating this to AL reveals several fundamental incompatibilities.

The Problems with AL

1. No Unsigned Integers

In C, the FNV hash operates on unsigned 32-bit integers, which range from 0 to approximately 4 billion. In AL, integers are always signed, meaning they range from roughly -2 billion to +2 billion. The concept of integer overflow “wrapping around” that C relies on simply doesn’t exist in AL the same way.

2. No Hexadecimal Constants

The FNV prime is typically expressed in hex (0x01000193), but AL doesn’t support hex constant notation. Erik solved this the old-fashioned way — punching the number into his trusty HP 42s calculator to convert it to decimal: 2166136261.

3. String Indexing Differences

C strings are zero-indexed (and technically just pointers to characters), while AL strings are one-indexed. The C code uses pointer arithmetic to walk through the string; in AL, you use a standard for loop from 1 to the string length.

4. Characters as Numbers

In C, a char is simultaneously a character and a number (an 8-bit value). In AL, you need to explicitly convert a character to its byte value to perform arithmetic on it.

The Solution: Big Integers and Custom Wrapping

Erik’s approach uses AL’s BigInteger data type to overcome the overflow limitations. Here’s the general strategy:

  1. Use BigInteger for all values — the hash, the prime, and the wrap boundary are all declared as BigInteger
  2. Implement wrapping manually — since BigInteger won’t overflow naturally, Erik implements the 32-bit unsigned wrap using modulo division. If the hash exceeds 2^32 (approximately 4 billion), take the remainder
  3. Convert characters to bytes — extract each character from the string and get its numeric byte value
  4. Custom bitwise XOR on BigInteger — since AL’s built-in type helper only supports bitwise XOR on regular (signed, 31-bit) integers, Erik copied the XOR function from the Type Helper codeunit and modified it to work with BigInteger across all 32 bits

Adapting the Type Helper’s Bitwise XOR

The built-in Type Helper codeunit in Business Central has a bitwise XOR function (there’s a separate video on the channel about it). However, it operates on standard integers — which are signed, meaning it only processes 31 bits (with the 32nd bit reserved for the sign). Erik copied this function into his own codeunit, changed all the integer types to BigInteger, and updated the max bit count from 31 to 32 to handle the full unsigned range.

Debugging the Implementation

Erik walked through the execution with the debugger to verify correctness:

  • The prime value is set correctly (2166136261)
  • The wrap value is set to 2^32 (approximately 4 billion)
  • On the first iteration, the hash starts at 0, multiplied by the prime it stays 0, then XOR with the first character (106, a lowercase ‘j’) gives a hash of 106
  • On subsequent iterations, the multiplication produces values larger than the wrap boundary, triggering the modulo operation to keep the value within 32-bit unsigned range
  • The final result: 2267144173 — matching the expected FNV hash output

Key Techniques Summary

  • BigInteger to overcome AL’s signed integer limitation and avoid overflow errors
  • Manual wrapping using modulo division to simulate unsigned 32-bit integer behavior
  • Copied and adapted the bitwise XOR function from the Type Helper codeunit, changing it from Integer to BigInteger and expanding from 31 to 32 bits
  • HP 42s calculator for hex-to-decimal conversion (because AL doesn’t support hex literals with the L suffix for BigInteger constants)

Conclusion

What was 5 lines of C code turned into considerably more AL code — but it works. The key insight is that when you need to replicate low-level unsigned integer arithmetic in AL, BigInteger combined with manual modulo wrapping gives you a reliable path forward. The bitwise operations require a bit more effort since the built-in helpers assume signed integers, but copying and adapting the existing Type Helper code is a practical solution. This is a great example of how understanding what’s happening at the bit level in both languages is essential when porting algorithms between C and AL.