The code here is just for research purposes. You know the drill. Use any code at your own risk.

Sample Code:

// Sample.cpp
//
// Randy McNabb
// December 1, 2005
//
// DESCRIPTION
// 
//
// This program is intended to demonstrate
// the ability to effectively output bits 
// from the encoding process in blocks
// instead of bit by bit.
//
// The program takes two arguments, an input
// file name and an output file name which
// are assigned to stdin and stdout. Full
// 32 bit values are used for the high and
// low registers. A single set bit is 
// written to the output file to flush the
// encoder as it is intended for the decoder
// to supply 0 bits past the end of the file.
// Output bytes are filled from left to right
// in both output examples.
//
// The model is a simple segmented cumulative
// table to decrease the number of updates
// needed to maintain the frequencies. 
//
// Pre-compiler directives are used to cut
// out code not used by the chosen output
// method. Define Use_Block_Output the 
// enable block output of the encoded data
// or comment it out the use the usual encoding
// method described in the 1987 CACM article by 
// Witten, Neal, and Cleary. 
//
// I offer my apologies for any lack in
// programming skills.
//

// Comment out to output bit by bit
#define Use_Block_Output

#include <stdio.h>
#include <time.h>
#include <memory.h> 

// routines
void Flush_Buffer();
void EncodeSymbol(unsigned char symbol);
void IntializeEncoder();
void StartModel();
void UpdateModel(unsigned long symbol);
unsigned long Read_Data(unsigned long bits_needed);

// Encoder variables
unsigned long low;
unsigned long high;
unsigned long hold_bits;
unsigned long bit_count;
unsigned long code;
// output stuff
#define BUFFERSIZE 65536
#define ROOMFORCARRY 8
#define BUFFERPADDING BUFFERSIZE + ROOMFORCARRY + 4
unsigned char outbuffer[BUFFERSIZE + BUFFERPADDING];
unsigned char *currentbyte = outbuffer;
unsigned char *bufferoverrun = outbuffer + BUFFERSIZE;

#ifdef Use_Block_Output
// ******** exclusive to block output **************
void Write_Data( unsigned long data, unsigned int bits_needed);
unsigned char *maxbuffer = bufferoverrun + ROOMFORCARRY;
unsigned char *outbyte = ((unsigned char *)&hold_bits) + 3;
// *************************************************
#else
// ******** exclusive to regular output ************
#define First_qtr 0x40000000ul 
#define Half (2*First_qtr) 
#define Third_qtr (3*First_qtr) 
unsigned long underflow_count;
// *************************************************
#endif

// Model stuff
#define ALPHABETCOUNT 256
#define MAXSCALE 0X40000000
unsigned long table[ALPHABETCOUNT + 1];
unsigned long toffs[(ALPHABETCOUNT>>4)+1] = {0};

int main(int argc, char* argv[])
{
    fprintf( stderr, "Encoding " );
    if ( argc > 1 ) {
        freopen( argv[ 1 ], "rb", stdin );
        fprintf( stderr, "%s", argv[ 1 ] );
    } else
        fprintf( stderr, "stdin" );
    fprintf( stderr, " to " );
    if ( argc > 2 ) {
        freopen( argv[ 2 ], "wb", stdout );
        fprintf( stderr, "%s", argv[ 2 ] );
    } else
        fprintf( stderr, "stdout" );
    fprintf( stderr, "\n" );

    int inchar; 
    // time check
    clock_t start, finish;
    double duration;
    start = clock(); 

    IntializeEncoder();
    StartModel();
    for (;;){ 
        // Loop through characters. //
        inchar = getc(stdin); // Read the next character. 
        if (inchar==EOF) break; // Exit loop on end-of-file.
        EncodeSymbol(inchar);
        UpdateModel(inchar);
    }
    Flush_Buffer();
    finish = clock();
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    fprintf( stderr, "Compression Time : %2.2f seconds\n", duration );

    return 0;
}

#ifdef Use_Block_Output

void Write_Data( unsigned long data, unsigned int bits_needed)
{ 
    if ( bits_needed > bit_count ){
        unsigned int leftoverbits = bits_needed - bit_count;
        Write_Data(data >> leftoverbits, bit_count);

        bit_count--; // don't write over last bit
        Write_Data(data & (~(0XFFFFFFFF << leftoverbits)), leftoverbits);
    }
    else{
        bit_count -= bits_needed;
        unsigned long t = hold_bits + (data << bit_count);
        // check for carry
        if ( t < hold_bits ){
            unsigned char *tempbyte = currentbyte - 1;
            while ( *tempbyte == 0XFF ){
                *tempbyte = 0;
                tempbyte--;
            }
            *tempbyte = *tempbyte + 1;;
        }
        hold_bits = t;
        // adjust to overlap first bit of next data written
        bit_count ++;
        // write whole bytes to outbuffer
        while ( bit_count < 25 ){
            *currentbyte = *outbyte;// outbyte points to highest byte of hold_bits
            currentbyte++;
            hold_bits <<= 8;
            bit_count += 8;
        } 
    }
    // is outbuffer full
    if ( currentbyte >= maxbuffer ){
        fwrite(outbuffer, 1, BUFFERSIZE, stdout);
        memcpy(outbuffer, bufferoverrun, BUFFERPADDING);
        currentbyte -= BUFFERSIZE;
    }
}

#else

inline void output_bit( int bit )
{ 
    hold_bits <<= 1; if (bit) hold_bits |= 0x01; 
    bit_count -= 1;
    if (bit_count==0) { 
        *currentbyte = (char) hold_bits; 
        currentbyte++;
        if ( currentbyte == bufferoverrun ){
            fwrite(outbuffer, 1, BUFFERSIZE, stdout);
            currentbyte = outbuffer;
        }
        bit_count = 8;
    }
}

#endif

void Flush_Buffer()
{
#ifdef Use_Block_Output

    Write_Data(1, 1);
    while ( hold_bits ){
        *currentbyte = *outbyte;
        currentbyte++;
        hold_bits <<= 8;
    }
#else
    output_bit(1);
    while ( underflow_count ){
        output_bit(0);
        underflow_count--;
    }
    hold_bits <<= bit_count;
    if ( (unsigned char )hold_bits ){
        *currentbyte = (char) hold_bits; 
        currentbyte++;
    }
#endif
    fwrite(outbuffer, 1, currentbyte - outbuffer, stdout);
}

void EncodeSymbol(unsigned char symbol)
{
    // calculate new high and low
    __int64 range = (__int64)high - low + 1;
    high = low + (unsigned long)((range * (table[symbol]+ toffs[symbol>>4])/(table[0]+toffs[0])) - 1);
    low = low + (unsigned long)(range * (table[symbol + 1]+ toffs[(symbol+1)>>4])/(table[0]+toffs[0]));

#ifdef Use_Block_Output
    unsigned long mincount;
    if ( high == low ){
        Write_Data(low, 32);
        low = 0;
        high = 0XFFFFFFFF;
        bit_count--; // don't write over last bit
    }
    else{
        // build mask
        unsigned long temp = high ^ low;
        unsigned long mask = (temp^((low & temp)<<1));
        // find index
        double hold = (temp^((low & temp)<<1));
        mincount = 1055-(*(((unsigned long*)&hold)+1)>>20);
        // output bits
        Write_Data(low >>(32 - mincount),  mincount--);
        // Update high and low
        low = (low << (mincount))&0X7FFFFFFF;
        high = (~((~high) << ( mincount))) | 0X80000000;
    }
#else
    for (;;) { 
        if (high<Half) {
            output_bit(0); 
            while ( underflow_count ){
                output_bit(1);
                underflow_count--;
            }
        }
        else if (low>=Half) { 
            output_bit(1);
            while ( underflow_count ){
                output_bit(0);
                underflow_count--;
            }
            low -= Half;
            high -= Half; 
        }
        else if (low>=First_qtr 
            && high<Third_qtr) { 
                underflow_count += 1;
                low -= First_qtr; 
                high -= First_qtr;
        }
        else break; 
        low = low<<1;
        high = (high<<1)+1; 
    }
#endif
}

void IntializeEncoder()
{
    low = 0;
    high = 0xFFFFFFFF;
    hold_bits = 0;
#ifdef Use_Block_Output
    bit_count = 32;
#else
    bit_count = 8;
    underflow_count = 0;
#endif
}

void StartModel()
{
    // set up main table
    int index = ALPHABETCOUNT;
    unsigned long current_count = 0;
    while ( index >= 0 ){
        table[index--] = current_count++;
    }
    // set up offset table
    index = (ALPHABETCOUNT >> 4);
    while ( index >= 0 ){
        toffs[index] = 0;
        index--;
    }
}

void UpdateModel(unsigned long symbol)
{
    int index = (symbol >> 4) - 1;
    while ( index >= 0 ){
        toffs[index--]++;
    }
    index = symbol & 0xF;
    while ( index >= 0 ){
        table[symbol--]++;
        index--;
    }
    // downsize model
    if ( (toffs[0]+table[0]) > MAXSCALE ){
        unsigned long hold;
        unsigned long last = 0;
        index = ALPHABETCOUNT - 1;
        while ( index >= 0 ){
            hold = table[index] + toffs[index >> 4];
            table[index] = ((hold - last) >> 2) + 1 + table[index + 1];
            last = hold;
            index--;
        }
        index = (ALPHABETCOUNT >> 4);
        while ( index >= 0 ){
            toffs[index] = 0;
            index--;
        }
    }
}