Skip to main content
better - more safe - definition of str1 variable,
Source Link
/* 
 * Copyright 2025 ... B. Samtleben, 
 * Based on others work, see below, alas in chaotic trial and error not all 
 * sources noted, will try to re-find origins for crediting. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Check to match / fullfill evtl. restrictions / copyrights of the origins. 
 * 2. As well for using / distributing source code as binaries. 
 * 3. Forward the following disclaimer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 */ 
 
// Issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers 
// with different names ( __int128, int_128? int_128_t? ), already confusing. 
// It doesn't provide read routine, print routine or print format specifier. 
// Working with such makes me feel blind, requires guessing, and likely 
// introduces errors. 
// The web is flooded with naive questions and - IMHO - insuffucient solutions 
// about the topic. The routines / macros provided here try to emulate: 
// - constants: 
//   INT_MAX, INT_MIN LONG_MAX ... by U128_MIN, U128_MAX, I128_MIN, I128_MAX, 
//   add. U128_MAX_DIV10, U128_MAX_MOD10, I128_MAX_DIV10 and I128_MAX_MOD10 
//   are added to handle overflow detection. 
// - input: 
//   strtol, strtoul, atoi by strtou128, strtoi128, 
// - output: 
//   u128tostr( str, x ) and i128tostr( str, x ) are intended to provide 
//   snprintf functionality, but without length limiter, 
//   printf functionality by printf( " %s ", i128tostr( x ) ) a little less 
//   complicated than quadmath_snprintf. 
 
// ressources: 
// "6.9 128-bit Integers" - int128 support in gcc / glibc, 
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html 
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128" 
// https://codeforces.com/blog/entry/75044 
// shortcomings AFAICT: console only, print fails for INT128_MIN, 
// "atoi, atol, atoll" - https://en.cppreference.com/w/c/string/byte/atoi, 
// "strtol, strtoll" - https://en.cppreference.com/w/c/string/byte/strtol, 
// "strtoul, strtoull" - https://en.cppreference.com/w/c/string/byte/strtoul, 
 
// tried to: xxxx 
// - not yet covered: 
//   Read multiple signs ( ++x, +-x ... ), 
//   Other print formatting. 
//   Other roots, no binary, octal or hex ... 
// In contrast to snprintf no length limit. 
// To know: defined behaviour, under- / overflows throw error and return 
// MAX in that direction. Like strto(u)l, unlike wrapping of atoi. 
// Caution: in contrast to overflow check for conversions calculations do wrap! 
// To know: signed and unsigned are not different, just different interpretation
// of the same bitstring. 
 
// Build: gcc or some c-compiler / libc with int128 support. 
// Build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware. 
// Standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c', 
// ignore warning about 'integer constant is so large that it is unsigned'. 
// Run with: './int128_test_5 xxxx (yy)' where xxxx is a string to read, convert, 
// re-convert and print. yy is optional to set the iterations for timing. 
// The macros before 'main' provide the functionality, 
// main has usage examples, tests some edge cases, compares under- / overflow 
// to strtoul, strtol and atoi, and checks arbitrary input from command line, 
// as well it provides simple performance timing. 
// Use in other programs: copy/paste from '#include' .. '#define TIMEITcu' into 
// your program, check for keyword or variable collisions test and then enjoy. 
// The rest is commented or - IMHO - self-explanatory. 
 
#include <errno.h>                                  // reg. e.g. errno, 
#include <stdio.h>                                  // reg. e.g. printf, putchar, 
#include <string.h>                                     // reg. e.g. strcpy, 
#include <stdbool.h>                                    // reg. e.g. bool, 
#include <limits.h>                                     // reg. e.g. UINT_MAX, 
#include <stdlib.h>                                     // reg. e.g. strtoul, 
#include <time.h>                                   // reg. e.g. clock(), 
#include <stdint.h>                                     // reg. e.g. __int128, 
#include <wchar.h>                                  // reg. e.g. wcstol, 
#include <inttypes.h>                                   // reg. e.g. imaxabs, 
 
#define _GNU_SOURCE                                     // acc. anonchatGTP required to use wchar.h, doesn't help for that, 
 
// #define int128 long long                                 // doesn't work, 
// #define int128 int128_t                              // doesn't work, 
// #define int128 int_128                               // doesn't work, 
 
#define int128 __int128                                 // try to avoid int128, __int128, __int128_t confusions, 
#define uint128 unsigned __int128                           // try to avoid long word 'unsigned', 
// #define int128 __int128_t                                // try to avoid int128, __int128, __int128_t confusions, 
// #define uint128 __uint128_t                              // try to avoid long word 'unsigned', 
                                            // not yet found which of above pairs is better, 
 
#define uint unsigned int                               // try to avoid long word 'unsigned', 
#define ulong unsigned long                                 // try to avoid long word 'unsigned', 
 
#define U128_MIN 0 
#define U128_MAX ( ( ( (uint128)( 0xFFFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF ) // gcc doesn't support constants > 64-bit?, 
#define U128_MAX_DIV10 ( U128_MAX / 10 )                        // constants for overflow check, 
#define U128_MAX_MOD10 ( U128_MAX % 10 ) 

#define I128_MAX ( ( ( (int128)( 0x7FFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF )  // gcc doesn't support constants > 64-bit?, 
#define I128_MAX_DIV10 ( I128_MAX / 10 )                        // constants for overflow check, 
#define I128_MAX_MOD10 ( I128_MAX % 10 ) 
#define I128_MIN ( -I128_MAX - 1 )                          // gcc doesn't support constants > 64-bit?,  
#define I128_MIN_DIV10 ( I128_MIN / 10 )                        // constants for overflow check, 
#define I128_MIN_MOD10 ( I128_MIN % 10 ) 
 
 
// volatile int i = 0;                                  // global variables defined before 'macros', 
// char str[ 45 ]; 
// char *ptr = str;
clock_t start1, end1; 
double reference = 1; 
 
uint128 strtou128( const char *s ) {                            // string to uint128, 
    const char *p = s; 
    uint128 val = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( *p == '-' ) {                               // Check against negative,  
        errno = 1; 
        perror( "error, don't try to convert negative string into positive value" ); 
        return( 0 ); 
    } 
 
    if( *p == '+' )                                 // Swallow '+', 
        p++; 
 
    while (*p >= '0' && *p <= '9') {                        // Convert string to number 
        if( ( val > U128_MAX_DIV10 ) ||                     // This seems costly, carry a counter and start at digit37? 
            ( ( val == U128_MAX_DIV10 ) && ( ( *p - '0' ) > U128_MAX_MOD10 ) ) ) { 
            errno = ERANGE; 
            perror( "error, uint128 overflow" ); 
            return( U128_MAX ); 
        } 
        val = (10 * val) + (*p - '0'); 
        p++; 
    } 
 
    return val; 
} 
 
int128 strtoi128( const char *s ) {                             // string to int128 from ???, 
    const char *p = s; 
    int128 val = 0; 
    bool neg = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( ( *p == '-' ) || ( *p == '+' ) ) {                      // Check for sign 
        neg = ( *p == '-' );                            // account '-', 
        p++;                                    // swalow '+', 
    } 
 
    if( !neg ) { 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val > I128_MAX_DIV10 ) || 
                ( ( val == I128_MAX_DIV10 ) && ( ( *p - '0' ) > I128_MAX_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 overflow" ); 
                return( I128_MAX ); 
            } 
        
        val = (10 * val) + (*p - '0'); 
        p++; 
        } 
    } 
 
    if( neg ) { 
        if( *p >= '0' && *p <= '9' ) {                      // Account 'neg', 
            val = ( ( 10 * val ) - ( *p - '0' ) ); 
            p++; 
        } 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val < I128_MIN_DIV10 ) || 
                ( ( val == I128_MIN_DIV10 ) && ( ( *p - '0' ) > -I128_MIN_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 underflow" ); 
                return( I128_MIN ); 
            } 
        val = ( 10 * val ) - ( *p - '0' ); 
        p++; 
        } 
    } 
 
    return val; 
} 
 
char* u128tostr( uint128 x ) {                          // converting uint128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 40 + 1 ] = { 0 };                      // definition includes termination, 
    int j = 40;                                     // start from right, 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    arr[ --j ] = ( x + '0');                            // set last ( most significant ) digit, 
    return arr + j;                                 // done, but if that works? 
} 
 
char* i128tostr( int128 x ) {                           // converting int128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 41 + 1 ] = { 0 };                      // definition includes termination, needs one add. byte for the sign, 
    int j = 41;                                     // start from right, 
    bool neg = ( x < 0 ); 
    if( neg ) { 
        arr[ --j ] = -( x % 10 ) + '0';                         // set next digit, 
        x = x / 10;                                 // strip from value, 
        x = -x;                                 // strip from value, 
    } else { 
        arr[ --j ] = x % 10 + '0';                      // set next digit, 
        x = x / 10;                                 // strip from value, 
    } 
 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    if( x > 0 )                                     // don't ad leading 0 to 1 digit negative values,  
        arr[ --j ] = ( x + '0');                        // set last ( most significant ) digit, 
    if( neg ) 
        arr[ --j ] = '-';                           // add sign, 
    return arr + j;                                 // done, but if that works? 
} 
 
#define TIMEITcu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1u; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1u, #expr, comment ) 
 
#define TIMEITci( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1d; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1i, #expr, comment ) 
 
#define TIMEITclu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1lu; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1lu, #expr, comment ) 
 
#define TIMEITcli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1ld; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1li, #expr, comment ) 
 
#define TIMEITcllu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, u128tostr( x1llu ), #expr, comment ) 
 
#define TIMEITclli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, i128tostr( x1lli ), #expr, comment ) 
 
#define TIMEITcstr( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, str1, #expr, comment ) 
 
 
int main( int argc, char *argv[] ) { 
 
    volatile uint128 x1llu; 
    volatile int128 x1lli; 
    volatile ulong x1lu; 
    volatile long x1li; 
    volatile uint x1u; 
    volatile int x1i; 
    char *str1;*str1 = malloc(41 * sizeof( char ) ); 
    int count = 1000; 
    wchar_t wide_str[20]; 

    if( argv[ 2 ] ) count = atoi( argv[ 2 ] ); 
 
    printf( " \n" ); 
 
    printf( "check availability of INT_128 \n\n" ); 
 
#ifdef __SIZEOF_INT128__
    printf( "size of INT128: %1d \n", __SIZEOF_INT128__ ); 
#else
    printf( "INT128 likely not supported. \n" ); 
#endif
 
    printf( "sizeof( intmax_t ) : %1d \n", sizeof( intmax_t ) ); 
    printf( "sizeof( uintmax_t ): %1d \n", sizeof( uintmax_t ) ); 
    printf( " \n" ); 
 
    printf( "check constants / references \n\n" ); 
 
    printf( "U128_MAX                : %s \n", u128tostr( U128_MAX ) ); 
    printf( "U128_MAX_DIV10          : %s \n", u128tostr( U128_MAX_DIV10 ) ); 
    printf( "U128_MAX_MOD10          : %s \n", u128tostr( U128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MAX                : %s \n", i128tostr( I128_MAX ) ); 
    printf( "I128_MAX_DIV10          : %s \n", i128tostr( I128_MAX_DIV10 ) ); 
    printf( "I128_MAX_MOD10          : %s \n", i128tostr( I128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MIN                : %s \n", i128tostr( I128_MIN ) ); 
    printf( "I128_MIN_DIV10          : %s \n", i128tostr( I128_MIN_DIV10 ) ); 
    printf( "I128_MIN_MOD10          : %s \n", i128tostr( I128_MIN_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "testing uint128: \n\n" ); 
 
    x1llu = 1;                                  // simple case, 
    printf( "simple 'x1llu = 1'      : %s \n", u128tostr( x1llu ) );        // print as string, 
 
    x1llu--;                                    // simple calculation, and checking 0, 
    printf( "'x1llu--'               : %s \n", u128tostr( x1llu )  ); 
 
    x1llu--;                                    // simple calculation, and checking wrap below 0, 
    printf( "'x1llu--' wrap below 0  : %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MIN;                               // checking MIN, 
    printf( "U128_MIN                : %s \n", u128tostr( U128_MIN ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MAX;                               // checking MAX, 
    printf( "U128_MAX                : %s \n", u128tostr( x1llu ) ); 
 
    x1llu++;                                    // check wrap above MAX, 
    printf( "'x1llu++' wrap above MAX: %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    printf( "testing int128: \n\n" ); 
 
    x1lli = 1;                                  // simple case, 
    printf( "simple 'x1ll1 = 1'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // simple calculation, and checking 0, 
    printf( "'x1ll1--' testing 0     : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking advaning into negtive, 
    printf( "'x1ll1--' go to negative: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MIN;                               // checking MIN, 
    printf( "'x1ll1 = I128_MIN'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking wrap below MIN, 
    printf( "'x1ll1--' wrap below MIN: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MAX;                               // checking MAX, 
    printf( "'x1ll1 = I128_MAX'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli++;                                    // checking wrap above MAX, 
    printf( "'x1ll1++' wrap above MAX: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -9223372036854775808ll ) ); // print the string, 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -18446744073709551616ll ) ); // print the string, 
 
    printf( "cross check vs. unsigned long int: \n\n" ); 
 
    x1lu = 1;                                   // simple case, 
    printf( "simple 'x1lu = 1'       : %1lu \n", x1lu );                // print the value, 
 
    x1lu--;                                     // simple calculation, and checking 0, 
    printf( "'x1lu--'                : %1lu \n", x1lu ); 
 
    x1lu--;                                     // simple calculation, and checking wrap below 0, 
    printf( "'x1lu--' wrap below 0   : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    x1lu = ULONG_MAX;                               // checking UINT_MAX, 
    printf( "'ULONG_MAX'             : %1lu \n", x1lu ); 
 
    x1lu++;                                     // checking wrap above MAX, 
    printf( "'x1lu++' wrap above MAX : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    printf( "cross check vs. long int: \n\n" ); 
 
    x1li = 1;                                   // simple case, 
    printf( "simple 'x1li = 1'       : %1ld \n", x1li );                // print the value, 
 
    x1li--;                                     // simple calculation, and checking 0, 
    printf( "'x1li--'                : %1ld \n", x1li ); 
 
    x1li--;                                     // simple calculation, and checking advance into negative, 
    printf( "'x1li--' advance to neg.: %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MIN;                                // checking INT_MIN, 
    printf( "'LONG_MIN'              : %1ld \n", x1li ); 
 
    x1li--;                                     // check wrap below MIN, 
    printf( "'x1li--' wrap below MIN : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MAX;                                // checking INT_MAX, 
    printf( "'LONG_MAX'              : %1ld \n", x1li ); 
 
    x1li++;                                     // check wrap above MAX, 
    printf( "'x1li++' wrap above MAX : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    printf( "cross check vs. unsigned int: \n\n" ); 
 
    x1u = 1;                                    // simple case, 
    printf( "simple 'x1u = 1'        : %1u \n", x1u );              // print the value, 
 
    x1u--;                                      // simple calculation, and checking 0, 
    printf( "'x1u--'                 : %1u \n", x1u ); 
 
    x1u--;                                      // simple calculation, and checking wrap below 0, 
    printf( "'x1u--' wrap below 0    : %1u \n", x1u ); 
    printf( " \n" ); 
 
    x1u = UINT_MAX;                                 // checking UINT_MAX, 
    printf( "'UINT_MAX'              : %1u \n", x1u ); 
 
    x1u++;                                      // checking wrap above MAX, 
    printf( "'x1u++' wrap above MAX  : %1u \n", x1u ); 
    printf( " \n" ); 
 
    printf( "cross check vs. int: \n\n" ); 
 
    x1i = 1;                                    // simple case, 
    printf( "simple 'x1i = 1'        : %1d \n", x1i );              // print the value, 
 
    x1i--;                                      // simple calculation, and checking 0, 
    printf( "'x1i--'                 : %1d \n", x1i ); 
 
    x1i--;                                      // simple calculation, and checking advance into negative, 
    printf( "'x1i--' advance to neg. : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MIN;                                  // checking INT_MIN, 
    printf( "'INT_MIN'               : %1d \n", x1i ); 
 
    x1i--;                                      // check wrap below MIN, 
    printf( "'x1i--' wrap below MIN  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MAX;                                  // checking INT_MAX, 
    printf( "'INT_MAX'               : %1d \n", x1i ); 
 
    x1i++;                                      // check wrap above MAX, 
    printf( "'x1i++' wrap above MAX  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    printf( "Check arbitrary values from command line argument: \n\n", x1li ); 
 
    x1llu = strtou128( argv[ 1 ] ); 
    printf( "input as uint128        : %s \n", u128tostr( x1llu ) ); 
    printf( "under- / overflow error < 0 and > U128_MAX, \n\n" ); 
 
    printf( "performance of uint128: \n" ); 
    TIMEITcllu( x1llu = strtou128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = u128tostr( x1llu ), count, "" ); 
    printf( " \n" ); 
 
    x1lli = strtoi128( argv[ 1 ] ); 
    printf( "input as int128         : %s \n", i128tostr( x1lli ) ); 
    printf( "under- / overflow error < I128_MIN and > I128_MAX \n\n" ); 
 
    printf( "performance of int128: \n" ); 
    TIMEITclli( x1lli = strtoi128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = i128tostr( x1lli ), count, "" ); 
    printf( " \n" ); 
 
    x1lu = strtoul( argv[ 1 ], NULL, 10 ); 
    printf( "input as unsig. longint : %1lu \n", x1lu ); 
    printf( "strtoul works up to ULONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to -ULONG_MAX, then stuck there, \n\n" ); 
 
    printf( "performance of ulong: \n\n" ); 
    TIMEITclu( x1lu = strtoul( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%lu", x1lu ), count, "" ); 
    printf( " \n" ); 
 
    x1li = strtol( argv[ 1 ], NULL, 10 ); 
    printf( "input as long int       : %1ld \n", x1li ); 
    printf( "strtol works up to LONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to LONG_MIN, then stuck there, \n\n" ); 
 
    printf( "performance of long: \n\n" ); 
    TIMEITcli( x1li = strtol( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%ld", x1li ), count, "" ); 
    printf( " \n" ); 
 
    x1u = atoi( argv[ 1 ] ); 
    printf( "input as uint           : %1u \n", x1u ); 
    printf( "atoi ( found no atou ) wrapping up to LONG_MAX, then stuck at \n" ); 
    printf( "4294967295 ( UINT_MAX ), in negative it wraps down to \n" ); 
    printf( "LONG-MIN, then stuck at 0. \n\n" ); 
 
    printf( "performance of uint: \n\n" ); 
    TIMEITcu( x1u = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 11, "%u", x1u ), count, "" ); 
    printf( " \n" ); 
 
    x1i = atoi( argv[ 1 ] ); 
    printf( "input as int            : %1d \n", x1i ); 
    printf( "atoi wraps up to LONG_MAX, then stuck at -1 \n" ); 
    printf( "in negative it wraps down to LONG_MIN, then stuck at 0. \n\n" ); 

    printf( "performance of atoi: \n\n" ); 
    TIMEITci( x1i = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 12, "%d", x1i ), count, "" ); 
    printf( " \n" ); 
 
// acc. anonchatGPT compiling with '-std=c99 helps to use wchar.h types ... not yet got it to work ... 
///     wide_str = \0; 
///     x1llu = wcstoull( argv[ 1 ], wide_str, 10 ); 
///     u128tostr( str, x1llu ); 
///     printf( "input as uint128        : %s \n", str ); 
 
    printf( "done \n \n" ); 
 
    return 0; 
} 
/* 
 * Copyright 2025 ... B. Samtleben, 
 * Based on others work, see below, alas in chaotic trial and error not all 
 * sources noted, will try to re-find origins for crediting. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Check to match / fullfill evtl. restrictions / copyrights of the origins. 
 * 2. As well for using / distributing source code as binaries. 
 * 3. Forward the following disclaimer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 */ 
 
// Issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers 
// with different names ( __int128, int_128? int_128_t? ), already confusing. 
// It doesn't provide read routine, print routine or print format specifier. 
// Working with such makes me feel blind, requires guessing, and likely 
// introduces errors. 
// The web is flooded with naive questions and - IMHO - insuffucient solutions 
// about the topic. The routines / macros provided here try to emulate: 
// - constants: 
//   INT_MAX, INT_MIN LONG_MAX ... by U128_MIN, U128_MAX, I128_MIN, I128_MAX, 
//   add. U128_MAX_DIV10, U128_MAX_MOD10, I128_MAX_DIV10 and I128_MAX_MOD10 
//   are added to handle overflow detection. 
// - input: 
//   strtol, strtoul, atoi by strtou128, strtoi128, 
// - output: 
//   u128tostr( str, x ) and i128tostr( str, x ) are intended to provide 
//   snprintf functionality, but without length limiter, 
//   printf functionality by printf( " %s ", i128tostr( x ) ) a little less 
//   complicated than quadmath_snprintf. 
 
// ressources: 
// "6.9 128-bit Integers" - int128 support in gcc / glibc, 
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html 
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128" 
// https://codeforces.com/blog/entry/75044 
// shortcomings AFAICT: console only, print fails for INT128_MIN, 
// "atoi, atol, atoll" - https://en.cppreference.com/w/c/string/byte/atoi, 
// "strtol, strtoll" - https://en.cppreference.com/w/c/string/byte/strtol, 
// "strtoul, strtoull" - https://en.cppreference.com/w/c/string/byte/strtoul, 
 
// tried to: xxxx 
// - not yet covered: 
//   Read multiple signs ( ++x, +-x ... ), 
//   Other print formatting. 
//   Other roots, no binary, octal or hex ... 
// In contrast to snprintf no length limit. 
// To know: defined behaviour, under- / overflows throw error and return 
// MAX in that direction. Like strto(u)l, unlike wrapping of atoi. 
// Caution: in contrast to overflow check for conversions calculations do wrap! 
// To know: signed and unsigned are not different, just different interpretation
// of the same bitstring. 
 
// Build: gcc or some c-compiler / libc with int128 support. 
// Build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware. 
// Standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c', 
// ignore warning about 'integer constant is so large that it is unsigned'. 
// Run with: './int128_test_5 xxxx (yy)' where xxxx is a string to read, convert, 
// re-convert and print. yy is optional to set the iterations for timing. 
// The macros before 'main' provide the functionality, 
// main has usage examples, tests some edge cases, compares under- / overflow 
// to strtoul, strtol and atoi, and checks arbitrary input from command line, 
// as well it provides simple performance timing. 
// Use in other programs: copy/paste from '#include' .. '#define TIMEITcu' into 
// your program, check for keyword or variable collisions test and then enjoy. 
// The rest is commented or - IMHO - self-explanatory. 
 
#include <errno.h>                                  // reg. e.g. errno, 
#include <stdio.h>                                  // reg. e.g. printf, putchar, 
#include <string.h>                                     // reg. e.g. strcpy, 
#include <stdbool.h>                                    // reg. e.g. bool, 
#include <limits.h>                                     // reg. e.g. UINT_MAX, 
#include <stdlib.h>                                     // reg. e.g. strtoul, 
#include <time.h>                                   // reg. e.g. clock(), 
#include <stdint.h>                                     // reg. e.g. __int128, 
#include <wchar.h>                                  // reg. e.g. wcstol, 
#include <inttypes.h>                                   // reg. e.g. imaxabs, 
 
#define _GNU_SOURCE                                     // acc. anonchatGTP required to use wchar.h, doesn't help for that, 
 
// #define int128 long long                                 // doesn't work, 
// #define int128 int128_t                              // doesn't work, 
// #define int128 int_128                               // doesn't work, 
 
#define int128 __int128                                 // try to avoid int128, __int128, __int128_t confusions, 
#define uint128 unsigned __int128                           // try to avoid long word 'unsigned', 
// #define int128 __int128_t                                // try to avoid int128, __int128, __int128_t confusions, 
// #define uint128 __uint128_t                              // try to avoid long word 'unsigned', 
                                            // not yet found which of above pairs is better, 
 
#define uint unsigned int                               // try to avoid long word 'unsigned', 
#define ulong unsigned long                                 // try to avoid long word 'unsigned', 
 
#define U128_MIN 0 
#define U128_MAX ( ( ( (uint128)( 0xFFFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF ) // gcc doesn't support constants > 64-bit?, 
#define U128_MAX_DIV10 ( U128_MAX / 10 )                        // constants for overflow check, 
#define U128_MAX_MOD10 ( U128_MAX % 10 ) 

#define I128_MAX ( ( ( (int128)( 0x7FFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF )  // gcc doesn't support constants > 64-bit?, 
#define I128_MAX_DIV10 ( I128_MAX / 10 )                        // constants for overflow check, 
#define I128_MAX_MOD10 ( I128_MAX % 10 ) 
#define I128_MIN ( -I128_MAX - 1 )                          // gcc doesn't support constants > 64-bit?,  
#define I128_MIN_DIV10 ( I128_MIN / 10 )                        // constants for overflow check, 
#define I128_MIN_MOD10 ( I128_MIN % 10 ) 
 
 
// volatile int i = 0;                                  // global variables defined before 'macros', 
// char str[ 45 ]; 
// char *ptr = str;
clock_t start1, end1; 
double reference = 1; 
 
uint128 strtou128( const char *s ) {                            // string to uint128, 
    const char *p = s; 
    uint128 val = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( *p == '-' ) {                               // Check against negative,  
        errno = 1; 
        perror( "error, don't try to convert negative string into positive value" ); 
        return( 0 ); 
    } 
 
    if( *p == '+' )                                 // Swallow '+', 
        p++; 
 
    while (*p >= '0' && *p <= '9') {                        // Convert string to number 
        if( ( val > U128_MAX_DIV10 ) ||                     // This seems costly, carry a counter and start at digit37? 
            ( ( val == U128_MAX_DIV10 ) && ( ( *p - '0' ) > U128_MAX_MOD10 ) ) ) { 
            errno = ERANGE; 
            perror( "error, uint128 overflow" ); 
            return( U128_MAX ); 
        } 
        val = (10 * val) + (*p - '0'); 
        p++; 
    } 
 
    return val; 
} 
 
int128 strtoi128( const char *s ) {                             // string to int128 from ???, 
    const char *p = s; 
    int128 val = 0; 
    bool neg = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( ( *p == '-' ) || ( *p == '+' ) ) {                      // Check for sign 
        neg = ( *p == '-' );                            // account '-', 
        p++;                                    // swalow '+', 
    } 
 
    if( !neg ) { 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val > I128_MAX_DIV10 ) || 
                ( ( val == I128_MAX_DIV10 ) && ( ( *p - '0' ) > I128_MAX_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 overflow" ); 
                return( I128_MAX ); 
            } 
        
        val = (10 * val) + (*p - '0'); 
        p++; 
        } 
    } 
 
    if( neg ) { 
        if( *p >= '0' && *p <= '9' ) {                      // Account 'neg', 
            val = ( ( 10 * val ) - ( *p - '0' ) ); 
            p++; 
        } 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val < I128_MIN_DIV10 ) || 
                ( ( val == I128_MIN_DIV10 ) && ( ( *p - '0' ) > -I128_MIN_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 underflow" ); 
                return( I128_MIN ); 
            } 
        val = ( 10 * val ) - ( *p - '0' ); 
        p++; 
        } 
    } 
 
    return val; 
} 
 
char* u128tostr( uint128 x ) {                          // converting uint128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 40 + 1 ] = { 0 };                      // definition includes termination, 
    int j = 40;                                     // start from right, 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    arr[ --j ] = ( x + '0');                            // set last ( most significant ) digit, 
    return arr + j;                                 // done, but if that works? 
} 
 
char* i128tostr( int128 x ) {                           // converting int128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 41 + 1 ] = { 0 };                      // definition includes termination, needs one add. byte for the sign, 
    int j = 41;                                     // start from right, 
    bool neg = ( x < 0 ); 
    if( neg ) { 
        arr[ --j ] = -( x % 10 ) + '0';                         // set next digit, 
        x = x / 10;                                 // strip from value, 
        x = -x;                                 // strip from value, 
    } else { 
        arr[ --j ] = x % 10 + '0';                      // set next digit, 
        x = x / 10;                                 // strip from value, 
    } 
 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    if( x > 0 )                                     // don't ad leading 0 to 1 digit negative values,  
        arr[ --j ] = ( x + '0');                        // set last ( most significant ) digit, 
    if( neg ) 
        arr[ --j ] = '-';                           // add sign, 
    return arr + j;                                 // done, but if that works? 
} 
 
#define TIMEITcu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1u; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1u, #expr, comment ) 
 
#define TIMEITci( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1d; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1i, #expr, comment ) 
 
#define TIMEITclu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1lu; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1lu, #expr, comment ) 
 
#define TIMEITcli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1ld; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1li, #expr, comment ) 
 
#define TIMEITcllu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, u128tostr( x1llu ), #expr, comment ) 
 
#define TIMEITclli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, i128tostr( x1lli ), #expr, comment ) 
 
#define TIMEITcstr( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, str1, #expr, comment ) 
 
 
int main( int argc, char *argv[] ) { 
 
    volatile uint128 x1llu; 
    volatile int128 x1lli; 
    volatile ulong x1lu; 
    volatile long x1li; 
    volatile uint x1u; 
    volatile int x1i; 
    char *str1; 
    int count = 1000; 
    wchar_t wide_str[20]; 

    if( argv[ 2 ] ) count = atoi( argv[ 2 ] ); 
 
    printf( " \n" ); 
 
    printf( "check availability of INT_128 \n\n" ); 
 
#ifdef __SIZEOF_INT128__
    printf( "size of INT128: %1d \n", __SIZEOF_INT128__ ); 
#else
    printf( "INT128 likely not supported. \n" ); 
#endif
 
    printf( "sizeof( intmax_t ) : %1d \n", sizeof( intmax_t ) ); 
    printf( "sizeof( uintmax_t ): %1d \n", sizeof( uintmax_t ) ); 
    printf( " \n" ); 
 
    printf( "check constants / references \n\n" ); 
 
    printf( "U128_MAX                : %s \n", u128tostr( U128_MAX ) ); 
    printf( "U128_MAX_DIV10          : %s \n", u128tostr( U128_MAX_DIV10 ) ); 
    printf( "U128_MAX_MOD10          : %s \n", u128tostr( U128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MAX                : %s \n", i128tostr( I128_MAX ) ); 
    printf( "I128_MAX_DIV10          : %s \n", i128tostr( I128_MAX_DIV10 ) ); 
    printf( "I128_MAX_MOD10          : %s \n", i128tostr( I128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MIN                : %s \n", i128tostr( I128_MIN ) ); 
    printf( "I128_MIN_DIV10          : %s \n", i128tostr( I128_MIN_DIV10 ) ); 
    printf( "I128_MIN_MOD10          : %s \n", i128tostr( I128_MIN_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "testing uint128: \n\n" ); 
 
    x1llu = 1;                                  // simple case, 
    printf( "simple 'x1llu = 1'      : %s \n", u128tostr( x1llu ) );        // print as string, 
 
    x1llu--;                                    // simple calculation, and checking 0, 
    printf( "'x1llu--'               : %s \n", u128tostr( x1llu )  ); 
 
    x1llu--;                                    // simple calculation, and checking wrap below 0, 
    printf( "'x1llu--' wrap below 0  : %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MIN;                               // checking MIN, 
    printf( "U128_MIN                : %s \n", u128tostr( U128_MIN ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MAX;                               // checking MAX, 
    printf( "U128_MAX                : %s \n", u128tostr( x1llu ) ); 
 
    x1llu++;                                    // check wrap above MAX, 
    printf( "'x1llu++' wrap above MAX: %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    printf( "testing int128: \n\n" ); 
 
    x1lli = 1;                                  // simple case, 
    printf( "simple 'x1ll1 = 1'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // simple calculation, and checking 0, 
    printf( "'x1ll1--' testing 0     : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking advaning into negtive, 
    printf( "'x1ll1--' go to negative: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MIN;                               // checking MIN, 
    printf( "'x1ll1 = I128_MIN'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking wrap below MIN, 
    printf( "'x1ll1--' wrap below MIN: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MAX;                               // checking MAX, 
    printf( "'x1ll1 = I128_MAX'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli++;                                    // checking wrap above MAX, 
    printf( "'x1ll1++' wrap above MAX: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -9223372036854775808ll ) ); // print the string, 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -18446744073709551616ll ) ); // print the string, 
 
    printf( "cross check vs. unsigned long int: \n\n" ); 
 
    x1lu = 1;                                   // simple case, 
    printf( "simple 'x1lu = 1'       : %1lu \n", x1lu );                // print the value, 
 
    x1lu--;                                     // simple calculation, and checking 0, 
    printf( "'x1lu--'                : %1lu \n", x1lu ); 
 
    x1lu--;                                     // simple calculation, and checking wrap below 0, 
    printf( "'x1lu--' wrap below 0   : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    x1lu = ULONG_MAX;                               // checking UINT_MAX, 
    printf( "'ULONG_MAX'             : %1lu \n", x1lu ); 
 
    x1lu++;                                     // checking wrap above MAX, 
    printf( "'x1lu++' wrap above MAX : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    printf( "cross check vs. long int: \n\n" ); 
 
    x1li = 1;                                   // simple case, 
    printf( "simple 'x1li = 1'       : %1ld \n", x1li );                // print the value, 
 
    x1li--;                                     // simple calculation, and checking 0, 
    printf( "'x1li--'                : %1ld \n", x1li ); 
 
    x1li--;                                     // simple calculation, and checking advance into negative, 
    printf( "'x1li--' advance to neg.: %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MIN;                                // checking INT_MIN, 
    printf( "'LONG_MIN'              : %1ld \n", x1li ); 
 
    x1li--;                                     // check wrap below MIN, 
    printf( "'x1li--' wrap below MIN : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MAX;                                // checking INT_MAX, 
    printf( "'LONG_MAX'              : %1ld \n", x1li ); 
 
    x1li++;                                     // check wrap above MAX, 
    printf( "'x1li++' wrap above MAX : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    printf( "cross check vs. unsigned int: \n\n" ); 
 
    x1u = 1;                                    // simple case, 
    printf( "simple 'x1u = 1'        : %1u \n", x1u );              // print the value, 
 
    x1u--;                                      // simple calculation, and checking 0, 
    printf( "'x1u--'                 : %1u \n", x1u ); 
 
    x1u--;                                      // simple calculation, and checking wrap below 0, 
    printf( "'x1u--' wrap below 0    : %1u \n", x1u ); 
    printf( " \n" ); 
 
    x1u = UINT_MAX;                                 // checking UINT_MAX, 
    printf( "'UINT_MAX'              : %1u \n", x1u ); 
 
    x1u++;                                      // checking wrap above MAX, 
    printf( "'x1u++' wrap above MAX  : %1u \n", x1u ); 
    printf( " \n" ); 
 
    printf( "cross check vs. int: \n\n" ); 
 
    x1i = 1;                                    // simple case, 
    printf( "simple 'x1i = 1'        : %1d \n", x1i );              // print the value, 
 
    x1i--;                                      // simple calculation, and checking 0, 
    printf( "'x1i--'                 : %1d \n", x1i ); 
 
    x1i--;                                      // simple calculation, and checking advance into negative, 
    printf( "'x1i--' advance to neg. : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MIN;                                  // checking INT_MIN, 
    printf( "'INT_MIN'               : %1d \n", x1i ); 
 
    x1i--;                                      // check wrap below MIN, 
    printf( "'x1i--' wrap below MIN  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MAX;                                  // checking INT_MAX, 
    printf( "'INT_MAX'               : %1d \n", x1i ); 
 
    x1i++;                                      // check wrap above MAX, 
    printf( "'x1i++' wrap above MAX  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    printf( "Check arbitrary values from command line argument: \n\n", x1li ); 
 
    x1llu = strtou128( argv[ 1 ] ); 
    printf( "input as uint128        : %s \n", u128tostr( x1llu ) ); 
    printf( "under- / overflow error < 0 and > U128_MAX, \n\n" ); 
 
    printf( "performance of uint128: \n" ); 
    TIMEITcllu( x1llu = strtou128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = u128tostr( x1llu ), count, "" ); 
    printf( " \n" ); 
 
    x1lli = strtoi128( argv[ 1 ] ); 
    printf( "input as int128         : %s \n", i128tostr( x1lli ) ); 
    printf( "under- / overflow error < I128_MIN and > I128_MAX \n\n" ); 
 
    printf( "performance of int128: \n" ); 
    TIMEITclli( x1lli = strtoi128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = i128tostr( x1lli ), count, "" ); 
    printf( " \n" ); 
 
    x1lu = strtoul( argv[ 1 ], NULL, 10 ); 
    printf( "input as unsig. longint : %1lu \n", x1lu ); 
    printf( "strtoul works up to ULONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to -ULONG_MAX, then stuck there, \n\n" ); 
 
    printf( "performance of ulong: \n\n" ); 
    TIMEITclu( x1lu = strtoul( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%lu", x1lu ), count, "" ); 
    printf( " \n" ); 
 
    x1li = strtol( argv[ 1 ], NULL, 10 ); 
    printf( "input as long int       : %1ld \n", x1li ); 
    printf( "strtol works up to LONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to LONG_MIN, then stuck there, \n\n" ); 
 
    printf( "performance of long: \n\n" ); 
    TIMEITcli( x1li = strtol( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%ld", x1li ), count, "" ); 
    printf( " \n" ); 
 
    x1u = atoi( argv[ 1 ] ); 
    printf( "input as uint           : %1u \n", x1u ); 
    printf( "atoi ( found no atou ) wrapping up to LONG_MAX, then stuck at \n" ); 
    printf( "4294967295 ( UINT_MAX ), in negative it wraps down to \n" ); 
    printf( "LONG-MIN, then stuck at 0. \n\n" ); 
 
    printf( "performance of uint: \n\n" ); 
    TIMEITcu( x1u = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 11, "%u", x1u ), count, "" ); 
    printf( " \n" ); 
 
    x1i = atoi( argv[ 1 ] ); 
    printf( "input as int            : %1d \n", x1i ); 
    printf( "atoi wraps up to LONG_MAX, then stuck at -1 \n" ); 
    printf( "in negative it wraps down to LONG_MIN, then stuck at 0. \n\n" ); 

    printf( "performance of atoi: \n\n" ); 
    TIMEITci( x1i = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 12, "%d", x1i ), count, "" ); 
    printf( " \n" ); 
 
// acc. anonchatGPT compiling with '-std=c99 helps to use wchar.h types ... not yet got it to work ... 
///     wide_str = \0; 
///     x1llu = wcstoull( argv[ 1 ], wide_str, 10 ); 
///     u128tostr( str, x1llu ); 
///     printf( "input as uint128        : %s \n", str ); 
 
    printf( "done \n \n" ); 
 
    return 0; 
} 
/* 
 * Copyright 2025 ... B. Samtleben, 
 * Based on others work, see below, alas in chaotic trial and error not all 
 * sources noted, will try to re-find origins for crediting. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Check to match / fullfill evtl. restrictions / copyrights of the origins. 
 * 2. As well for using / distributing source code as binaries. 
 * 3. Forward the following disclaimer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 */ 
 
// Issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers 
// with different names ( __int128, int_128? int_128_t? ), already confusing. 
// It doesn't provide read routine, print routine or print format specifier. 
// Working with such makes me feel blind, requires guessing, and likely 
// introduces errors. 
// The web is flooded with naive questions and - IMHO - insuffucient solutions 
// about the topic. The routines / macros provided here try to emulate: 
// - constants: 
//   INT_MAX, INT_MIN LONG_MAX ... by U128_MIN, U128_MAX, I128_MIN, I128_MAX, 
//   add. U128_MAX_DIV10, U128_MAX_MOD10, I128_MAX_DIV10 and I128_MAX_MOD10 
//   are added to handle overflow detection. 
// - input: 
//   strtol, strtoul, atoi by strtou128, strtoi128, 
// - output: 
//   u128tostr( str, x ) and i128tostr( str, x ) are intended to provide 
//   snprintf functionality, but without length limiter, 
//   printf functionality by printf( " %s ", i128tostr( x ) ) a little less 
//   complicated than quadmath_snprintf. 
 
// ressources: 
// "6.9 128-bit Integers" - int128 support in gcc / glibc, 
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html 
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128" 
// https://codeforces.com/blog/entry/75044 
// shortcomings AFAICT: console only, print fails for INT128_MIN, 
// "atoi, atol, atoll" - https://en.cppreference.com/w/c/string/byte/atoi, 
// "strtol, strtoll" - https://en.cppreference.com/w/c/string/byte/strtol, 
// "strtoul, strtoull" - https://en.cppreference.com/w/c/string/byte/strtoul, 
 
// tried to: xxxx 
// - not yet covered: 
//   Read multiple signs ( ++x, +-x ... ), 
//   Other print formatting. 
//   Other roots, no binary, octal or hex ... 
// In contrast to snprintf no length limit. 
// To know: defined behaviour, under- / overflows throw error and return 
// MAX in that direction. Like strto(u)l, unlike wrapping of atoi. 
// Caution: in contrast to overflow check for conversions calculations do wrap! 
// To know: signed and unsigned are not different, just different interpretation
// of the same bitstring. 
 
// Build: gcc or some c-compiler / libc with int128 support. 
// Build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware. 
// Standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c', 
// ignore warning about 'integer constant is so large that it is unsigned'. 
// Run with: './int128_test_5 xxxx (yy)' where xxxx is a string to read, convert, 
// re-convert and print. yy is optional to set the iterations for timing. 
// The macros before 'main' provide the functionality, 
// main has usage examples, tests some edge cases, compares under- / overflow 
// to strtoul, strtol and atoi, and checks arbitrary input from command line, 
// as well it provides simple performance timing. 
// Use in other programs: copy/paste from '#include' .. '#define TIMEITcu' into 
// your program, check for keyword or variable collisions test and then enjoy. 
// The rest is commented or - IMHO - self-explanatory. 
 
#include <errno.h>                                  // reg. e.g. errno, 
#include <stdio.h>                                  // reg. e.g. printf, putchar, 
#include <string.h>                                     // reg. e.g. strcpy, 
#include <stdbool.h>                                    // reg. e.g. bool, 
#include <limits.h>                                     // reg. e.g. UINT_MAX, 
#include <stdlib.h>                                     // reg. e.g. strtoul, 
#include <time.h>                                   // reg. e.g. clock(), 
#include <stdint.h>                                     // reg. e.g. __int128, 
#include <wchar.h>                                  // reg. e.g. wcstol, 
#include <inttypes.h>                                   // reg. e.g. imaxabs, 
 
#define _GNU_SOURCE                                     // acc. anonchatGTP required to use wchar.h, doesn't help for that, 
 
// #define int128 long long                                 // doesn't work, 
// #define int128 int128_t                              // doesn't work, 
// #define int128 int_128                               // doesn't work, 
 
#define int128 __int128                                 // try to avoid int128, __int128, __int128_t confusions, 
#define uint128 unsigned __int128                           // try to avoid long word 'unsigned', 
// #define int128 __int128_t                                // try to avoid int128, __int128, __int128_t confusions, 
// #define uint128 __uint128_t                              // try to avoid long word 'unsigned', 
                                            // not yet found which of above pairs is better, 
 
#define uint unsigned int                               // try to avoid long word 'unsigned', 
#define ulong unsigned long                                 // try to avoid long word 'unsigned', 
 
#define U128_MIN 0 
#define U128_MAX ( ( ( (uint128)( 0xFFFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF ) // gcc doesn't support constants > 64-bit?, 
#define U128_MAX_DIV10 ( U128_MAX / 10 )                        // constants for overflow check, 
#define U128_MAX_MOD10 ( U128_MAX % 10 ) 

#define I128_MAX ( ( ( (int128)( 0x7FFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF )  // gcc doesn't support constants > 64-bit?, 
#define I128_MAX_DIV10 ( I128_MAX / 10 )                        // constants for overflow check, 
#define I128_MAX_MOD10 ( I128_MAX % 10 ) 
#define I128_MIN ( -I128_MAX - 1 )                          // gcc doesn't support constants > 64-bit?,  
#define I128_MIN_DIV10 ( I128_MIN / 10 )                        // constants for overflow check, 
#define I128_MIN_MOD10 ( I128_MIN % 10 ) 
 
 
// volatile int i = 0;                                  // global variables defined before 'macros', 
// char str[ 45 ]; 
// char *ptr = str;
clock_t start1, end1; 
double reference = 1; 
 
uint128 strtou128( const char *s ) {                            // string to uint128, 
    const char *p = s; 
    uint128 val = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( *p == '-' ) {                               // Check against negative,  
        errno = 1; 
        perror( "error, don't try to convert negative string into positive value" ); 
        return( 0 ); 
    } 
 
    if( *p == '+' )                                 // Swallow '+', 
        p++; 
 
    while (*p >= '0' && *p <= '9') {                        // Convert string to number 
        if( ( val > U128_MAX_DIV10 ) ||                     // This seems costly, carry a counter and start at digit37? 
            ( ( val == U128_MAX_DIV10 ) && ( ( *p - '0' ) > U128_MAX_MOD10 ) ) ) { 
            errno = ERANGE; 
            perror( "error, uint128 overflow" ); 
            return( U128_MAX ); 
        } 
        val = (10 * val) + (*p - '0'); 
        p++; 
    } 
 
    return val; 
} 
 
int128 strtoi128( const char *s ) {                             // string to int128 from ???, 
    const char *p = s; 
    int128 val = 0; 
    bool neg = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( ( *p == '-' ) || ( *p == '+' ) ) {                      // Check for sign 
        neg = ( *p == '-' );                            // account '-', 
        p++;                                    // swalow '+', 
    } 
 
    if( !neg ) { 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val > I128_MAX_DIV10 ) || 
                ( ( val == I128_MAX_DIV10 ) && ( ( *p - '0' ) > I128_MAX_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 overflow" ); 
                return( I128_MAX ); 
            } 
        
        val = (10 * val) + (*p - '0'); 
        p++; 
        } 
    } 
 
    if( neg ) { 
        if( *p >= '0' && *p <= '9' ) {                      // Account 'neg', 
            val = ( ( 10 * val ) - ( *p - '0' ) ); 
            p++; 
        } 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val < I128_MIN_DIV10 ) || 
                ( ( val == I128_MIN_DIV10 ) && ( ( *p - '0' ) > -I128_MIN_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 underflow" ); 
                return( I128_MIN ); 
            } 
        val = ( 10 * val ) - ( *p - '0' ); 
        p++; 
        } 
    } 
 
    return val; 
} 
 
char* u128tostr( uint128 x ) {                          // converting uint128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 40 + 1 ] = { 0 };                      // definition includes termination, 
    int j = 40;                                     // start from right, 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    arr[ --j ] = ( x + '0');                            // set last ( most significant ) digit, 
    return arr + j;                                 // done, but if that works? 
} 
 
char* i128tostr( int128 x ) {                           // converting int128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 41 + 1 ] = { 0 };                      // definition includes termination, needs one add. byte for the sign, 
    int j = 41;                                     // start from right, 
    bool neg = ( x < 0 ); 
    if( neg ) { 
        arr[ --j ] = -( x % 10 ) + '0';                         // set next digit, 
        x = x / 10;                                 // strip from value, 
        x = -x;                                 // strip from value, 
    } else { 
        arr[ --j ] = x % 10 + '0';                      // set next digit, 
        x = x / 10;                                 // strip from value, 
    } 
 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    if( x > 0 )                                     // don't ad leading 0 to 1 digit negative values,  
        arr[ --j ] = ( x + '0');                        // set last ( most significant ) digit, 
    if( neg ) 
        arr[ --j ] = '-';                           // add sign, 
    return arr + j;                                 // done, but if that works? 
} 
 
#define TIMEITcu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1u; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1u, #expr, comment ) 
 
#define TIMEITci( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1d; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1i, #expr, comment ) 
 
#define TIMEITclu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1lu; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1lu, #expr, comment ) 
 
#define TIMEITcli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1ld; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1li, #expr, comment ) 
 
#define TIMEITcllu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, u128tostr( x1llu ), #expr, comment ) 
 
#define TIMEITclli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, i128tostr( x1lli ), #expr, comment ) 
 
#define TIMEITcstr( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, str1, #expr, comment ) 
 
 
int main( int argc, char *argv[] ) { 
 
    volatile uint128 x1llu; 
    volatile int128 x1lli; 
    volatile ulong x1lu; 
    volatile long x1li; 
    volatile uint x1u; 
    volatile int x1i; 
    char *str1 = malloc(41 * sizeof( char ) ); 
    int count = 1000; 
    wchar_t wide_str[20]; 

    if( argv[ 2 ] ) count = atoi( argv[ 2 ] ); 
 
    printf( " \n" ); 
 
    printf( "check availability of INT_128 \n\n" ); 
 
#ifdef __SIZEOF_INT128__
    printf( "size of INT128: %1d \n", __SIZEOF_INT128__ ); 
#else
    printf( "INT128 likely not supported. \n" ); 
#endif
 
    printf( "sizeof( intmax_t ) : %1d \n", sizeof( intmax_t ) ); 
    printf( "sizeof( uintmax_t ): %1d \n", sizeof( uintmax_t ) ); 
    printf( " \n" ); 
 
    printf( "check constants / references \n\n" ); 
 
    printf( "U128_MAX                : %s \n", u128tostr( U128_MAX ) ); 
    printf( "U128_MAX_DIV10          : %s \n", u128tostr( U128_MAX_DIV10 ) ); 
    printf( "U128_MAX_MOD10          : %s \n", u128tostr( U128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MAX                : %s \n", i128tostr( I128_MAX ) ); 
    printf( "I128_MAX_DIV10          : %s \n", i128tostr( I128_MAX_DIV10 ) ); 
    printf( "I128_MAX_MOD10          : %s \n", i128tostr( I128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MIN                : %s \n", i128tostr( I128_MIN ) ); 
    printf( "I128_MIN_DIV10          : %s \n", i128tostr( I128_MIN_DIV10 ) ); 
    printf( "I128_MIN_MOD10          : %s \n", i128tostr( I128_MIN_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "testing uint128: \n\n" ); 
 
    x1llu = 1;                                  // simple case, 
    printf( "simple 'x1llu = 1'      : %s \n", u128tostr( x1llu ) );        // print as string, 
 
    x1llu--;                                    // simple calculation, and checking 0, 
    printf( "'x1llu--'               : %s \n", u128tostr( x1llu )  ); 
 
    x1llu--;                                    // simple calculation, and checking wrap below 0, 
    printf( "'x1llu--' wrap below 0  : %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MIN;                               // checking MIN, 
    printf( "U128_MIN                : %s \n", u128tostr( U128_MIN ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MAX;                               // checking MAX, 
    printf( "U128_MAX                : %s \n", u128tostr( x1llu ) ); 
 
    x1llu++;                                    // check wrap above MAX, 
    printf( "'x1llu++' wrap above MAX: %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    printf( "testing int128: \n\n" ); 
 
    x1lli = 1;                                  // simple case, 
    printf( "simple 'x1ll1 = 1'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // simple calculation, and checking 0, 
    printf( "'x1ll1--' testing 0     : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking advaning into negtive, 
    printf( "'x1ll1--' go to negative: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MIN;                               // checking MIN, 
    printf( "'x1ll1 = I128_MIN'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking wrap below MIN, 
    printf( "'x1ll1--' wrap below MIN: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MAX;                               // checking MAX, 
    printf( "'x1ll1 = I128_MAX'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli++;                                    // checking wrap above MAX, 
    printf( "'x1ll1++' wrap above MAX: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -9223372036854775808ll ) ); // print the string, 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -18446744073709551616ll ) ); // print the string, 
 
    printf( "cross check vs. unsigned long int: \n\n" ); 
 
    x1lu = 1;                                   // simple case, 
    printf( "simple 'x1lu = 1'       : %1lu \n", x1lu );                // print the value, 
 
    x1lu--;                                     // simple calculation, and checking 0, 
    printf( "'x1lu--'                : %1lu \n", x1lu ); 
 
    x1lu--;                                     // simple calculation, and checking wrap below 0, 
    printf( "'x1lu--' wrap below 0   : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    x1lu = ULONG_MAX;                               // checking UINT_MAX, 
    printf( "'ULONG_MAX'             : %1lu \n", x1lu ); 
 
    x1lu++;                                     // checking wrap above MAX, 
    printf( "'x1lu++' wrap above MAX : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    printf( "cross check vs. long int: \n\n" ); 
 
    x1li = 1;                                   // simple case, 
    printf( "simple 'x1li = 1'       : %1ld \n", x1li );                // print the value, 
 
    x1li--;                                     // simple calculation, and checking 0, 
    printf( "'x1li--'                : %1ld \n", x1li ); 
 
    x1li--;                                     // simple calculation, and checking advance into negative, 
    printf( "'x1li--' advance to neg.: %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MIN;                                // checking INT_MIN, 
    printf( "'LONG_MIN'              : %1ld \n", x1li ); 
 
    x1li--;                                     // check wrap below MIN, 
    printf( "'x1li--' wrap below MIN : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MAX;                                // checking INT_MAX, 
    printf( "'LONG_MAX'              : %1ld \n", x1li ); 
 
    x1li++;                                     // check wrap above MAX, 
    printf( "'x1li++' wrap above MAX : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    printf( "cross check vs. unsigned int: \n\n" ); 
 
    x1u = 1;                                    // simple case, 
    printf( "simple 'x1u = 1'        : %1u \n", x1u );              // print the value, 
 
    x1u--;                                      // simple calculation, and checking 0, 
    printf( "'x1u--'                 : %1u \n", x1u ); 
 
    x1u--;                                      // simple calculation, and checking wrap below 0, 
    printf( "'x1u--' wrap below 0    : %1u \n", x1u ); 
    printf( " \n" ); 
 
    x1u = UINT_MAX;                                 // checking UINT_MAX, 
    printf( "'UINT_MAX'              : %1u \n", x1u ); 
 
    x1u++;                                      // checking wrap above MAX, 
    printf( "'x1u++' wrap above MAX  : %1u \n", x1u ); 
    printf( " \n" ); 
 
    printf( "cross check vs. int: \n\n" ); 
 
    x1i = 1;                                    // simple case, 
    printf( "simple 'x1i = 1'        : %1d \n", x1i );              // print the value, 
 
    x1i--;                                      // simple calculation, and checking 0, 
    printf( "'x1i--'                 : %1d \n", x1i ); 
 
    x1i--;                                      // simple calculation, and checking advance into negative, 
    printf( "'x1i--' advance to neg. : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MIN;                                  // checking INT_MIN, 
    printf( "'INT_MIN'               : %1d \n", x1i ); 
 
    x1i--;                                      // check wrap below MIN, 
    printf( "'x1i--' wrap below MIN  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MAX;                                  // checking INT_MAX, 
    printf( "'INT_MAX'               : %1d \n", x1i ); 
 
    x1i++;                                      // check wrap above MAX, 
    printf( "'x1i++' wrap above MAX  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    printf( "Check arbitrary values from command line argument: \n\n", x1li ); 
 
    x1llu = strtou128( argv[ 1 ] ); 
    printf( "input as uint128        : %s \n", u128tostr( x1llu ) ); 
    printf( "under- / overflow error < 0 and > U128_MAX, \n\n" ); 
 
    printf( "performance of uint128: \n" ); 
    TIMEITcllu( x1llu = strtou128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = u128tostr( x1llu ), count, "" ); 
    printf( " \n" ); 
 
    x1lli = strtoi128( argv[ 1 ] ); 
    printf( "input as int128         : %s \n", i128tostr( x1lli ) ); 
    printf( "under- / overflow error < I128_MIN and > I128_MAX \n\n" ); 
 
    printf( "performance of int128: \n" ); 
    TIMEITclli( x1lli = strtoi128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = i128tostr( x1lli ), count, "" ); 
    printf( " \n" ); 
 
    x1lu = strtoul( argv[ 1 ], NULL, 10 ); 
    printf( "input as unsig. longint : %1lu \n", x1lu ); 
    printf( "strtoul works up to ULONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to -ULONG_MAX, then stuck there, \n\n" ); 
 
    printf( "performance of ulong: \n\n" ); 
    TIMEITclu( x1lu = strtoul( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%lu", x1lu ), count, "" ); 
    printf( " \n" ); 
 
    x1li = strtol( argv[ 1 ], NULL, 10 ); 
    printf( "input as long int       : %1ld \n", x1li ); 
    printf( "strtol works up to LONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to LONG_MIN, then stuck there, \n\n" ); 
 
    printf( "performance of long: \n\n" ); 
    TIMEITcli( x1li = strtol( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%ld", x1li ), count, "" ); 
    printf( " \n" ); 
 
    x1u = atoi( argv[ 1 ] ); 
    printf( "input as uint           : %1u \n", x1u ); 
    printf( "atoi ( found no atou ) wrapping up to LONG_MAX, then stuck at \n" ); 
    printf( "4294967295 ( UINT_MAX ), in negative it wraps down to \n" ); 
    printf( "LONG-MIN, then stuck at 0. \n\n" ); 
 
    printf( "performance of uint: \n\n" ); 
    TIMEITcu( x1u = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 11, "%u", x1u ), count, "" ); 
    printf( " \n" ); 
 
    x1i = atoi( argv[ 1 ] ); 
    printf( "input as int            : %1d \n", x1i ); 
    printf( "atoi wraps up to LONG_MAX, then stuck at -1 \n" ); 
    printf( "in negative it wraps down to LONG_MIN, then stuck at 0. \n\n" ); 

    printf( "performance of atoi: \n\n" ); 
    TIMEITci( x1i = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 12, "%d", x1i ), count, "" ); 
    printf( " \n" ); 
 
// acc. anonchatGPT compiling with '-std=c99 helps to use wchar.h types ... not yet got it to work ... 
///     wide_str = \0; 
///     x1llu = wcstoull( argv[ 1 ], wide_str, 10 ); 
///     u128tostr( str, x1llu ); 
///     printf( "input as uint128        : %s \n", str ); 
 
    printf( "done \n \n" ); 
 
    return 0; 
} 
added new version of functions and code to demonstrate, including performance check.
Source Link

[edit] Edited to show new version of routines and program, see at the end, improved? [/edit ]

[edit ]
new version:

/* 
 * Copyright 2025 ... B. Samtleben, 
 * Based on others work, see below, alas in chaotic trial and error not all 
 * sources noted, will try to re-find origins for crediting. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Check to match / fullfill evtl. restrictions / copyrights of the origins. 
 * 2. As well for using / distributing source code as binaries. 
 * 3. Forward the following disclaimer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 */ 
 
// Issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers 
// with different names ( __int128, int_128? int_128_t? ), already confusing. 
// It doesn't provide read routine, print routine or print format specifier. 
// Working with such makes me feel blind, requires guessing, and likely 
// introduces errors. 
// The web is flooded with naive questions and - IMHO - insuffucient solutions 
// about the topic. The routines / macros provided here try to emulate: 
// - constants: 
//   INT_MAX, INT_MIN LONG_MAX ... by U128_MIN, U128_MAX, I128_MIN, I128_MAX, 
//   add. U128_MAX_DIV10, U128_MAX_MOD10, I128_MAX_DIV10 and I128_MAX_MOD10 
//   are added to handle overflow detection. 
// - input: 
//   strtol, strtoul, atoi by strtou128, strtoi128, 
// - output: 
//   u128tostr( str, x ) and i128tostr( str, x ) are intended to provide 
//   snprintf functionality, but without length limiter, 
//   printf functionality by printf( " %s ", i128tostr( x ) ) a little less 
//   complicated than quadmath_snprintf. 
 
// ressources: 
// "6.9 128-bit Integers" - int128 support in gcc / glibc, 
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html 
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128" 
// https://codeforces.com/blog/entry/75044 
// shortcomings AFAICT: console only, print fails for INT128_MIN, 
// "atoi, atol, atoll" - https://en.cppreference.com/w/c/string/byte/atoi, 
// "strtol, strtoll" - https://en.cppreference.com/w/c/string/byte/strtol, 
// "strtoul, strtoull" - https://en.cppreference.com/w/c/string/byte/strtoul, 
 
// tried to: xxxx 
// - not yet covered: 
//   Read multiple signs ( ++x, +-x ... ), 
//   Other print formatting. 
//   Other roots, no binary, octal or hex ... 
// In contrast to snprintf no length limit. 
// To know: defined behaviour, under- / overflows throw error and return 
// MAX in that direction. Like strto(u)l, unlike wrapping of atoi. 
// Caution: in contrast to overflow check for conversions calculations do wrap! 
// To know: signed and unsigned are not different, just different interpretation
// of the same bitstring. 
 
// Build: gcc or some c-compiler / libc with int128 support. 
// Build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware. 
// Standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c', 
// ignore warning about 'integer constant is so large that it is unsigned'. 
// Run with: './int128_test_5 xxxx (yy)' where xxxx is a string to read, convert, 
// re-convert and print. yy is optional to set the iterations for timing. 
// The macros before 'main' provide the functionality, 
// main has usage examples, tests some edge cases, compares under- / overflow 
// to strtoul, strtol and atoi, and checks arbitrary input from command line, 
// as well it provides simple performance timing. 
// Use in other programs: copy/paste from '#include' .. '#define TIMEITcu' into 
// your program, check for keyword or variable collisions test and then enjoy. 
// The rest is commented or - IMHO - self-explanatory. 
 
#include <errno.h>                                  // reg. e.g. errno, 
#include <stdio.h>                                  // reg. e.g. printf, putchar, 
#include <string.h>                                     // reg. e.g. strcpy, 
#include <stdbool.h>                                    // reg. e.g. bool, 
#include <limits.h>                                     // reg. e.g. UINT_MAX, 
#include <stdlib.h>                                     // reg. e.g. strtoul, 
#include <time.h>                                   // reg. e.g. clock(), 
#include <stdint.h>                                     // reg. e.g. __int128, 
#include <wchar.h>                                  // reg. e.g. wcstol, 
#include <inttypes.h>                                   // reg. e.g. imaxabs, 
 
#define _GNU_SOURCE                                     // acc. anonchatGTP required to use wchar.h, doesn't help for that, 
 
// #define int128 long long                                 // doesn't work, 
// #define int128 int128_t                              // doesn't work, 
// #define int128 int_128                               // doesn't work, 
 
#define int128 __int128                                 // try to avoid int128, __int128, __int128_t confusions, 
#define uint128 unsigned __int128                           // try to avoid long word 'unsigned', 
// #define int128 __int128_t                                // try to avoid int128, __int128, __int128_t confusions, 
// #define uint128 __uint128_t                              // try to avoid long word 'unsigned', 
                                            // not yet found which of above pairs is better, 
 
#define uint unsigned int                               // try to avoid long word 'unsigned', 
#define ulong unsigned long                                 // try to avoid long word 'unsigned', 
 
#define U128_MIN 0 
#define U128_MAX ( ( ( (uint128)( 0xFFFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF ) // gcc doesn't support constants > 64-bit?, 
#define U128_MAX_DIV10 ( U128_MAX / 10 )                        // constants for overflow check, 
#define U128_MAX_MOD10 ( U128_MAX % 10 ) 

#define I128_MAX ( ( ( (int128)( 0x7FFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF )  // gcc doesn't support constants > 64-bit?, 
#define I128_MAX_DIV10 ( I128_MAX / 10 )                        // constants for overflow check, 
#define I128_MAX_MOD10 ( I128_MAX % 10 ) 
#define I128_MIN ( -I128_MAX - 1 )                          // gcc doesn't support constants > 64-bit?,  
#define I128_MIN_DIV10 ( I128_MIN / 10 )                        // constants for overflow check, 
#define I128_MIN_MOD10 ( I128_MIN % 10 ) 
 
 
// volatile int i = 0;                                  // global variables defined before 'macros', 
// char str[ 45 ]; 
// char *ptr = str;
clock_t start1, end1; 
double reference = 1; 
 
uint128 strtou128( const char *s ) {                            // string to uint128, 
    const char *p = s; 
    uint128 val = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( *p == '-' ) {                               // Check against negative,  
        errno = 1; 
        perror( "error, don't try to convert negative string into positive value" ); 
        return( 0 ); 
    } 
 
    if( *p == '+' )                                 // Swallow '+', 
        p++; 
 
    while (*p >= '0' && *p <= '9') {                        // Convert string to number 
        if( ( val > U128_MAX_DIV10 ) ||                     // This seems costly, carry a counter and start at digit37? 
            ( ( val == U128_MAX_DIV10 ) && ( ( *p - '0' ) > U128_MAX_MOD10 ) ) ) { 
            errno = ERANGE; 
            perror( "error, uint128 overflow" ); 
            return( U128_MAX ); 
        } 
        val = (10 * val) + (*p - '0'); 
        p++; 
    } 
 
    return val; 
} 
 
int128 strtoi128( const char *s ) {                             // string to int128 from ???, 
    const char *p = s; 
    int128 val = 0; 
    bool neg = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( ( *p == '-' ) || ( *p == '+' ) ) {                      // Check for sign 
        neg = ( *p == '-' );                            // account '-', 
        p++;                                    // swalow '+', 
    } 
 
    if( !neg ) { 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val > I128_MAX_DIV10 ) || 
                ( ( val == I128_MAX_DIV10 ) && ( ( *p - '0' ) > I128_MAX_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 overflow" ); 
                return( I128_MAX ); 
            } 
        
        val = (10 * val) + (*p - '0'); 
        p++; 
        } 
    } 
 
    if( neg ) { 
        if( *p >= '0' && *p <= '9' ) {                      // Account 'neg', 
            val = ( ( 10 * val ) - ( *p - '0' ) ); 
            p++; 
        } 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val < I128_MIN_DIV10 ) || 
                ( ( val == I128_MIN_DIV10 ) && ( ( *p - '0' ) > -I128_MIN_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 underflow" ); 
                return( I128_MIN ); 
            } 
        val = ( 10 * val ) - ( *p - '0' ); 
        p++; 
        } 
    } 
 
    return val; 
} 
 
char* u128tostr( uint128 x ) {                          // converting uint128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 40 + 1 ] = { 0 };                      // definition includes termination, 
    int j = 40;                                     // start from right, 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    arr[ --j ] = ( x + '0');                            // set last ( most significant ) digit, 
    return arr + j;                                 // done, but if that works? 
} 
 
char* i128tostr( int128 x ) {                           // converting int128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 41 + 1 ] = { 0 };                      // definition includes termination, needs one add. byte for the sign, 
    int j = 41;                                     // start from right, 
    bool neg = ( x < 0 ); 
    if( neg ) { 
        arr[ --j ] = -( x % 10 ) + '0';                         // set next digit, 
        x = x / 10;                                 // strip from value, 
        x = -x;                                 // strip from value, 
    } else { 
        arr[ --j ] = x % 10 + '0';                      // set next digit, 
        x = x / 10;                                 // strip from value, 
    } 
 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    if( x > 0 )                                     // don't ad leading 0 to 1 digit negative values,  
        arr[ --j ] = ( x + '0');                        // set last ( most significant ) digit, 
    if( neg ) 
        arr[ --j ] = '-';                           // add sign, 
    return arr + j;                                 // done, but if that works? 
} 
 
#define TIMEITcu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1u; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1u, #expr, comment ) 
 
#define TIMEITci( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1d; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1i, #expr, comment ) 
 
#define TIMEITclu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1lu; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1lu, #expr, comment ) 
 
#define TIMEITcli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1ld; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1li, #expr, comment ) 
 
#define TIMEITcllu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, u128tostr( x1llu ), #expr, comment ) 
 
#define TIMEITclli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, i128tostr( x1lli ), #expr, comment ) 
 
#define TIMEITcstr( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, str1, #expr, comment ) 
 
 
int main( int argc, char *argv[] ) { 
 
    volatile uint128 x1llu; 
    volatile int128 x1lli; 
    volatile ulong x1lu; 
    volatile long x1li; 
    volatile uint x1u; 
    volatile int x1i; 
    char *str1; 
    int count = 1000; 
    wchar_t wide_str[20]; 

    if( argv[ 2 ] ) count = atoi( argv[ 2 ] ); 
 
    printf( " \n" ); 
 
    printf( "check availability of INT_128 \n\n" ); 
 
#ifdef __SIZEOF_INT128__
    printf( "size of INT128: %1d \n", __SIZEOF_INT128__ ); 
#else
    printf( "INT128 likely not supported. \n" ); 
#endif
 
    printf( "sizeof( intmax_t ) : %1d \n", sizeof( intmax_t ) ); 
    printf( "sizeof( uintmax_t ): %1d \n", sizeof( uintmax_t ) ); 
    printf( " \n" ); 
 
    printf( "check constants / references \n\n" ); 
 
    printf( "U128_MAX                : %s \n", u128tostr( U128_MAX ) ); 
    printf( "U128_MAX_DIV10          : %s \n", u128tostr( U128_MAX_DIV10 ) ); 
    printf( "U128_MAX_MOD10          : %s \n", u128tostr( U128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MAX                : %s \n", i128tostr( I128_MAX ) ); 
    printf( "I128_MAX_DIV10          : %s \n", i128tostr( I128_MAX_DIV10 ) ); 
    printf( "I128_MAX_MOD10          : %s \n", i128tostr( I128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MIN                : %s \n", i128tostr( I128_MIN ) ); 
    printf( "I128_MIN_DIV10          : %s \n", i128tostr( I128_MIN_DIV10 ) ); 
    printf( "I128_MIN_MOD10          : %s \n", i128tostr( I128_MIN_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "testing uint128: \n\n" ); 
 
    x1llu = 1;                                  // simple case, 
    printf( "simple 'x1llu = 1'      : %s \n", u128tostr( x1llu ) );        // print as string, 
 
    x1llu--;                                    // simple calculation, and checking 0, 
    printf( "'x1llu--'               : %s \n", u128tostr( x1llu )  ); 
 
    x1llu--;                                    // simple calculation, and checking wrap below 0, 
    printf( "'x1llu--' wrap below 0  : %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MIN;                               // checking MIN, 
    printf( "U128_MIN                : %s \n", u128tostr( U128_MIN ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MAX;                               // checking MAX, 
    printf( "U128_MAX                : %s \n", u128tostr( x1llu ) ); 
 
    x1llu++;                                    // check wrap above MAX, 
    printf( "'x1llu++' wrap above MAX: %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    printf( "testing int128: \n\n" ); 
 
    x1lli = 1;                                  // simple case, 
    printf( "simple 'x1ll1 = 1'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // simple calculation, and checking 0, 
    printf( "'x1ll1--' testing 0     : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking advaning into negtive, 
    printf( "'x1ll1--' go to negative: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MIN;                               // checking MIN, 
    printf( "'x1ll1 = I128_MIN'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking wrap below MIN, 
    printf( "'x1ll1--' wrap below MIN: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MAX;                               // checking MAX, 
    printf( "'x1ll1 = I128_MAX'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli++;                                    // checking wrap above MAX, 
    printf( "'x1ll1++' wrap above MAX: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -9223372036854775808ll ) ); // print the string, 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -18446744073709551616ll ) ); // print the string, 
 
    printf( "cross check vs. unsigned long int: \n\n" ); 
 
    x1lu = 1;                                   // simple case, 
    printf( "simple 'x1lu = 1'       : %1lu \n", x1lu );                // print the value, 
 
    x1lu--;                                     // simple calculation, and checking 0, 
    printf( "'x1lu--'                : %1lu \n", x1lu ); 
 
    x1lu--;                                     // simple calculation, and checking wrap below 0, 
    printf( "'x1lu--' wrap below 0   : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    x1lu = ULONG_MAX;                               // checking UINT_MAX, 
    printf( "'ULONG_MAX'             : %1lu \n", x1lu ); 
 
    x1lu++;                                     // checking wrap above MAX, 
    printf( "'x1lu++' wrap above MAX : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    printf( "cross check vs. long int: \n\n" ); 
 
    x1li = 1;                                   // simple case, 
    printf( "simple 'x1li = 1'       : %1ld \n", x1li );                // print the value, 
 
    x1li--;                                     // simple calculation, and checking 0, 
    printf( "'x1li--'                : %1ld \n", x1li ); 
 
    x1li--;                                     // simple calculation, and checking advance into negative, 
    printf( "'x1li--' advance to neg.: %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MIN;                                // checking INT_MIN, 
    printf( "'LONG_MIN'              : %1ld \n", x1li ); 
 
    x1li--;                                     // check wrap below MIN, 
    printf( "'x1li--' wrap below MIN : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MAX;                                // checking INT_MAX, 
    printf( "'LONG_MAX'              : %1ld \n", x1li ); 
 
    x1li++;                                     // check wrap above MAX, 
    printf( "'x1li++' wrap above MAX : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    printf( "cross check vs. unsigned int: \n\n" ); 
 
    x1u = 1;                                    // simple case, 
    printf( "simple 'x1u = 1'        : %1u \n", x1u );              // print the value, 
 
    x1u--;                                      // simple calculation, and checking 0, 
    printf( "'x1u--'                 : %1u \n", x1u ); 
 
    x1u--;                                      // simple calculation, and checking wrap below 0, 
    printf( "'x1u--' wrap below 0    : %1u \n", x1u ); 
    printf( " \n" ); 
 
    x1u = UINT_MAX;                                 // checking UINT_MAX, 
    printf( "'UINT_MAX'              : %1u \n", x1u ); 
 
    x1u++;                                      // checking wrap above MAX, 
    printf( "'x1u++' wrap above MAX  : %1u \n", x1u ); 
    printf( " \n" ); 
 
    printf( "cross check vs. int: \n\n" ); 
 
    x1i = 1;                                    // simple case, 
    printf( "simple 'x1i = 1'        : %1d \n", x1i );              // print the value, 
 
    x1i--;                                      // simple calculation, and checking 0, 
    printf( "'x1i--'                 : %1d \n", x1i ); 
 
    x1i--;                                      // simple calculation, and checking advance into negative, 
    printf( "'x1i--' advance to neg. : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MIN;                                  // checking INT_MIN, 
    printf( "'INT_MIN'               : %1d \n", x1i ); 
 
    x1i--;                                      // check wrap below MIN, 
    printf( "'x1i--' wrap below MIN  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MAX;                                  // checking INT_MAX, 
    printf( "'INT_MAX'               : %1d \n", x1i ); 
 
    x1i++;                                      // check wrap above MAX, 
    printf( "'x1i++' wrap above MAX  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    printf( "Check arbitrary values from command line argument: \n\n", x1li ); 
 
    x1llu = strtou128( argv[ 1 ] ); 
    printf( "input as uint128        : %s \n", u128tostr( x1llu ) ); 
    printf( "under- / overflow error < 0 and > U128_MAX, \n\n" ); 
 
    printf( "performance of uint128: \n" ); 
    TIMEITcllu( x1llu = strtou128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = u128tostr( x1llu ), count, "" ); 
    printf( " \n" ); 
 
    x1lli = strtoi128( argv[ 1 ] ); 
    printf( "input as int128         : %s \n", i128tostr( x1lli ) ); 
    printf( "under- / overflow error < I128_MIN and > I128_MAX \n\n" ); 
 
    printf( "performance of int128: \n" ); 
    TIMEITclli( x1lli = strtoi128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = i128tostr( x1lli ), count, "" ); 
    printf( " \n" ); 
 
    x1lu = strtoul( argv[ 1 ], NULL, 10 ); 
    printf( "input as unsig. longint : %1lu \n", x1lu ); 
    printf( "strtoul works up to ULONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to -ULONG_MAX, then stuck there, \n\n" ); 
 
    printf( "performance of ulong: \n\n" ); 
    TIMEITclu( x1lu = strtoul( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%lu", x1lu ), count, "" ); 
    printf( " \n" ); 
 
    x1li = strtol( argv[ 1 ], NULL, 10 ); 
    printf( "input as long int       : %1ld \n", x1li ); 
    printf( "strtol works up to LONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to LONG_MIN, then stuck there, \n\n" ); 
 
    printf( "performance of long: \n\n" ); 
    TIMEITcli( x1li = strtol( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%ld", x1li ), count, "" ); 
    printf( " \n" ); 
 
    x1u = atoi( argv[ 1 ] ); 
    printf( "input as uint           : %1u \n", x1u ); 
    printf( "atoi ( found no atou ) wrapping up to LONG_MAX, then stuck at \n" ); 
    printf( "4294967295 ( UINT_MAX ), in negative it wraps down to \n" ); 
    printf( "LONG-MIN, then stuck at 0. \n\n" ); 
 
    printf( "performance of uint: \n\n" ); 
    TIMEITcu( x1u = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 11, "%u", x1u ), count, "" ); 
    printf( " \n" ); 
 
    x1i = atoi( argv[ 1 ] ); 
    printf( "input as int            : %1d \n", x1i ); 
    printf( "atoi wraps up to LONG_MAX, then stuck at -1 \n" ); 
    printf( "in negative it wraps down to LONG_MIN, then stuck at 0. \n\n" ); 

    printf( "performance of atoi: \n\n" ); 
    TIMEITci( x1i = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 12, "%d", x1i ), count, "" ); 
    printf( " \n" ); 
 
// acc. anonchatGPT compiling with '-std=c99 helps to use wchar.h types ... not yet got it to work ... 
///     wide_str = \0; 
///     x1llu = wcstoull( argv[ 1 ], wide_str, 10 ); 
///     u128tostr( str, x1llu ); 
///     printf( "input as uint128        : %s \n", str ); 
 
    printf( "done \n \n" ); 
 
    return 0; 
} 

re-check appreciated.
[/edit ]

[edit] Edited to show new version of routines and program, see at the end, improved? [/edit ]

[edit ]
new version:

/* 
 * Copyright 2025 ... B. Samtleben, 
 * Based on others work, see below, alas in chaotic trial and error not all 
 * sources noted, will try to re-find origins for crediting. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Check to match / fullfill evtl. restrictions / copyrights of the origins. 
 * 2. As well for using / distributing source code as binaries. 
 * 3. Forward the following disclaimer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 */ 
 
// Issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers 
// with different names ( __int128, int_128? int_128_t? ), already confusing. 
// It doesn't provide read routine, print routine or print format specifier. 
// Working with such makes me feel blind, requires guessing, and likely 
// introduces errors. 
// The web is flooded with naive questions and - IMHO - insuffucient solutions 
// about the topic. The routines / macros provided here try to emulate: 
// - constants: 
//   INT_MAX, INT_MIN LONG_MAX ... by U128_MIN, U128_MAX, I128_MIN, I128_MAX, 
//   add. U128_MAX_DIV10, U128_MAX_MOD10, I128_MAX_DIV10 and I128_MAX_MOD10 
//   are added to handle overflow detection. 
// - input: 
//   strtol, strtoul, atoi by strtou128, strtoi128, 
// - output: 
//   u128tostr( str, x ) and i128tostr( str, x ) are intended to provide 
//   snprintf functionality, but without length limiter, 
//   printf functionality by printf( " %s ", i128tostr( x ) ) a little less 
//   complicated than quadmath_snprintf. 
 
// ressources: 
// "6.9 128-bit Integers" - int128 support in gcc / glibc, 
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html 
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128" 
// https://codeforces.com/blog/entry/75044 
// shortcomings AFAICT: console only, print fails for INT128_MIN, 
// "atoi, atol, atoll" - https://en.cppreference.com/w/c/string/byte/atoi, 
// "strtol, strtoll" - https://en.cppreference.com/w/c/string/byte/strtol, 
// "strtoul, strtoull" - https://en.cppreference.com/w/c/string/byte/strtoul, 
 
// tried to: xxxx 
// - not yet covered: 
//   Read multiple signs ( ++x, +-x ... ), 
//   Other print formatting. 
//   Other roots, no binary, octal or hex ... 
// In contrast to snprintf no length limit. 
// To know: defined behaviour, under- / overflows throw error and return 
// MAX in that direction. Like strto(u)l, unlike wrapping of atoi. 
// Caution: in contrast to overflow check for conversions calculations do wrap! 
// To know: signed and unsigned are not different, just different interpretation
// of the same bitstring. 
 
// Build: gcc or some c-compiler / libc with int128 support. 
// Build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware. 
// Standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c', 
// ignore warning about 'integer constant is so large that it is unsigned'. 
// Run with: './int128_test_5 xxxx (yy)' where xxxx is a string to read, convert, 
// re-convert and print. yy is optional to set the iterations for timing. 
// The macros before 'main' provide the functionality, 
// main has usage examples, tests some edge cases, compares under- / overflow 
// to strtoul, strtol and atoi, and checks arbitrary input from command line, 
// as well it provides simple performance timing. 
// Use in other programs: copy/paste from '#include' .. '#define TIMEITcu' into 
// your program, check for keyword or variable collisions test and then enjoy. 
// The rest is commented or - IMHO - self-explanatory. 
 
#include <errno.h>                                  // reg. e.g. errno, 
#include <stdio.h>                                  // reg. e.g. printf, putchar, 
#include <string.h>                                     // reg. e.g. strcpy, 
#include <stdbool.h>                                    // reg. e.g. bool, 
#include <limits.h>                                     // reg. e.g. UINT_MAX, 
#include <stdlib.h>                                     // reg. e.g. strtoul, 
#include <time.h>                                   // reg. e.g. clock(), 
#include <stdint.h>                                     // reg. e.g. __int128, 
#include <wchar.h>                                  // reg. e.g. wcstol, 
#include <inttypes.h>                                   // reg. e.g. imaxabs, 
 
#define _GNU_SOURCE                                     // acc. anonchatGTP required to use wchar.h, doesn't help for that, 
 
// #define int128 long long                                 // doesn't work, 
// #define int128 int128_t                              // doesn't work, 
// #define int128 int_128                               // doesn't work, 
 
#define int128 __int128                                 // try to avoid int128, __int128, __int128_t confusions, 
#define uint128 unsigned __int128                           // try to avoid long word 'unsigned', 
// #define int128 __int128_t                                // try to avoid int128, __int128, __int128_t confusions, 
// #define uint128 __uint128_t                              // try to avoid long word 'unsigned', 
                                            // not yet found which of above pairs is better, 
 
#define uint unsigned int                               // try to avoid long word 'unsigned', 
#define ulong unsigned long                                 // try to avoid long word 'unsigned', 
 
#define U128_MIN 0 
#define U128_MAX ( ( ( (uint128)( 0xFFFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF ) // gcc doesn't support constants > 64-bit?, 
#define U128_MAX_DIV10 ( U128_MAX / 10 )                        // constants for overflow check, 
#define U128_MAX_MOD10 ( U128_MAX % 10 ) 

#define I128_MAX ( ( ( (int128)( 0x7FFFFFFFFFFFFFFF ) ) << 64 ) + 0xFFFFFFFFFFFFFFFF )  // gcc doesn't support constants > 64-bit?, 
#define I128_MAX_DIV10 ( I128_MAX / 10 )                        // constants for overflow check, 
#define I128_MAX_MOD10 ( I128_MAX % 10 ) 
#define I128_MIN ( -I128_MAX - 1 )                          // gcc doesn't support constants > 64-bit?,  
#define I128_MIN_DIV10 ( I128_MIN / 10 )                        // constants for overflow check, 
#define I128_MIN_MOD10 ( I128_MIN % 10 ) 
 
 
// volatile int i = 0;                                  // global variables defined before 'macros', 
// char str[ 45 ]; 
// char *ptr = str;
clock_t start1, end1; 
double reference = 1; 
 
uint128 strtou128( const char *s ) {                            // string to uint128, 
    const char *p = s; 
    uint128 val = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( *p == '-' ) {                               // Check against negative,  
        errno = 1; 
        perror( "error, don't try to convert negative string into positive value" ); 
        return( 0 ); 
    } 
 
    if( *p == '+' )                                 // Swallow '+', 
        p++; 
 
    while (*p >= '0' && *p <= '9') {                        // Convert string to number 
        if( ( val > U128_MAX_DIV10 ) ||                     // This seems costly, carry a counter and start at digit37? 
            ( ( val == U128_MAX_DIV10 ) && ( ( *p - '0' ) > U128_MAX_MOD10 ) ) ) { 
            errno = ERANGE; 
            perror( "error, uint128 overflow" ); 
            return( U128_MAX ); 
        } 
        val = (10 * val) + (*p - '0'); 
        p++; 
    } 
 
    return val; 
} 
 
int128 strtoi128( const char *s ) {                             // string to int128 from ???, 
    const char *p = s; 
    int128 val = 0; 
    bool neg = 0; 
 
    while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||               // Skip leading whitespace 
        (*p == '\f') || (*p == '\r') || (*p == '\v')) 
        p++; 
 
    if( ( *p == '-' ) || ( *p == '+' ) ) {                      // Check for sign 
        neg = ( *p == '-' );                            // account '-', 
        p++;                                    // swalow '+', 
    } 
 
    if( !neg ) { 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val > I128_MAX_DIV10 ) || 
                ( ( val == I128_MAX_DIV10 ) && ( ( *p - '0' ) > I128_MAX_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 overflow" ); 
                return( I128_MAX ); 
            } 
        
        val = (10 * val) + (*p - '0'); 
        p++; 
        } 
    } 
 
    if( neg ) { 
        if( *p >= '0' && *p <= '9' ) {                      // Account 'neg', 
            val = ( ( 10 * val ) - ( *p - '0' ) ); 
            p++; 
        } 
        while (*p >= '0' && *p <= '9') {                    // Convert string to number, 
            if( ( val < I128_MIN_DIV10 ) || 
                ( ( val == I128_MIN_DIV10 ) && ( ( *p - '0' ) > -I128_MIN_MOD10 ) ) ) { 
                errno = ERANGE; 
                perror( "error, int128 underflow" ); 
                return( I128_MIN ); 
            } 
        val = ( 10 * val ) - ( *p - '0' ); 
        p++; 
        } 
    } 
 
    return val; 
} 
 
char* u128tostr( uint128 x ) {                          // converting uint128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 40 + 1 ] = { 0 };                      // definition includes termination, 
    int j = 40;                                     // start from right, 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    arr[ --j ] = ( x + '0');                            // set last ( most significant ) digit, 
    return arr + j;                                 // done, but if that works? 
} 
 
char* i128tostr( int128 x ) {                           // converting int128 into 0-terminated ASCII string, buffer approach, 
    static char arr[ 41 + 1 ] = { 0 };                      // definition includes termination, needs one add. byte for the sign, 
    int j = 41;                                     // start from right, 
    bool neg = ( x < 0 ); 
    if( neg ) { 
        arr[ --j ] = -( x % 10 ) + '0';                         // set next digit, 
        x = x / 10;                                 // strip from value, 
        x = -x;                                 // strip from value, 
    } else { 
        arr[ --j ] = x % 10 + '0';                      // set next digit, 
        x = x / 10;                                 // strip from value, 
    } 
 
    while( x > 9 ) {                                // iterate through value, 
        arr[ --j ] = ( x % 10 + '0' );                      // set next digit, 
        x /= 10;                                // strip from value, 
    } 
    if( x > 0 )                                     // don't ad leading 0 to 1 digit negative values,  
        arr[ --j ] = ( x + '0');                        // set last ( most significant ) digit, 
    if( neg ) 
        arr[ --j ] = '-';                           // add sign, 
    return arr + j;                                 // done, but if that works? 
} 
 
#define TIMEITcu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1u; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1u, #expr, comment ) 
 
#define TIMEITci( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1d; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1i, #expr, comment ) 
 
#define TIMEITclu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1lu; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1lu, #expr, comment ) 
 
#define TIMEITcli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%1ld; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, x1li, #expr, comment ) 
 
#define TIMEITcllu( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, u128tostr( x1llu ), #expr, comment ) 
 
#define TIMEITclli( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, i128tostr( x1lli ), #expr, comment ) 
 
#define TIMEITcstr( expr, N, comment ) \
    start1 = clock(); \
    for( int i = 1; i <= N; i++ ) \
    { \
        expr; \
    } \
    end1 = clock(); \
    printf( "%07d; %09.03f; %1d; '%s; %s; %s \n", end1 - start1, ( end1 - start1 ) / reference, N, str1, #expr, comment ) 
 
 
int main( int argc, char *argv[] ) { 
 
    volatile uint128 x1llu; 
    volatile int128 x1lli; 
    volatile ulong x1lu; 
    volatile long x1li; 
    volatile uint x1u; 
    volatile int x1i; 
    char *str1; 
    int count = 1000; 
    wchar_t wide_str[20]; 

    if( argv[ 2 ] ) count = atoi( argv[ 2 ] ); 
 
    printf( " \n" ); 
 
    printf( "check availability of INT_128 \n\n" ); 
 
#ifdef __SIZEOF_INT128__
    printf( "size of INT128: %1d \n", __SIZEOF_INT128__ ); 
#else
    printf( "INT128 likely not supported. \n" ); 
#endif
 
    printf( "sizeof( intmax_t ) : %1d \n", sizeof( intmax_t ) ); 
    printf( "sizeof( uintmax_t ): %1d \n", sizeof( uintmax_t ) ); 
    printf( " \n" ); 
 
    printf( "check constants / references \n\n" ); 
 
    printf( "U128_MAX                : %s \n", u128tostr( U128_MAX ) ); 
    printf( "U128_MAX_DIV10          : %s \n", u128tostr( U128_MAX_DIV10 ) ); 
    printf( "U128_MAX_MOD10          : %s \n", u128tostr( U128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MAX                : %s \n", i128tostr( I128_MAX ) ); 
    printf( "I128_MAX_DIV10          : %s \n", i128tostr( I128_MAX_DIV10 ) ); 
    printf( "I128_MAX_MOD10          : %s \n", i128tostr( I128_MAX_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "I128_MIN                : %s \n", i128tostr( I128_MIN ) ); 
    printf( "I128_MIN_DIV10          : %s \n", i128tostr( I128_MIN_DIV10 ) ); 
    printf( "I128_MIN_MOD10          : %s \n", i128tostr( I128_MIN_MOD10 ) ); 
    printf( " \n" ); 
 
    printf( "testing uint128: \n\n" ); 
 
    x1llu = 1;                                  // simple case, 
    printf( "simple 'x1llu = 1'      : %s \n", u128tostr( x1llu ) );        // print as string, 
 
    x1llu--;                                    // simple calculation, and checking 0, 
    printf( "'x1llu--'               : %s \n", u128tostr( x1llu )  ); 
 
    x1llu--;                                    // simple calculation, and checking wrap below 0, 
    printf( "'x1llu--' wrap below 0  : %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MIN;                               // checking MIN, 
    printf( "U128_MIN                : %s \n", u128tostr( U128_MIN ) ); 
    printf( " \n" ); 
 
    x1llu = U128_MAX;                               // checking MAX, 
    printf( "U128_MAX                : %s \n", u128tostr( x1llu ) ); 
 
    x1llu++;                                    // check wrap above MAX, 
    printf( "'x1llu++' wrap above MAX: %s \n", u128tostr( x1llu ) ); 
    printf( " \n" ); 
 
    printf( "testing int128: \n\n" ); 
 
    x1lli = 1;                                  // simple case, 
    printf( "simple 'x1ll1 = 1'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // simple calculation, and checking 0, 
    printf( "'x1ll1--' testing 0     : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking advaning into negtive, 
    printf( "'x1ll1--' go to negative: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MIN;                               // checking MIN, 
    printf( "'x1ll1 = I128_MIN'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli--;                                    // checking wrap below MIN, 
    printf( "'x1ll1--' wrap below MIN: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    x1lli = I128_MAX;                               // checking MAX, 
    printf( "'x1ll1 = I128_MAX'      : %s \n", i128tostr( x1lli ) );        // print the string, 
 
    x1lli++;                                    // checking wrap above MAX, 
    printf( "'x1ll1++' wrap above MAX: %s \n", i128tostr( x1lli ) );        // print the string, 
    printf( " \n" ); 
 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -9223372036854775808ll ) ); // print the string, 
    printf( "'ll' wraps at LONG_MAX  : %s \n\n", i128tostr( -18446744073709551616ll ) ); // print the string, 
 
    printf( "cross check vs. unsigned long int: \n\n" ); 
 
    x1lu = 1;                                   // simple case, 
    printf( "simple 'x1lu = 1'       : %1lu \n", x1lu );                // print the value, 
 
    x1lu--;                                     // simple calculation, and checking 0, 
    printf( "'x1lu--'                : %1lu \n", x1lu ); 
 
    x1lu--;                                     // simple calculation, and checking wrap below 0, 
    printf( "'x1lu--' wrap below 0   : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    x1lu = ULONG_MAX;                               // checking UINT_MAX, 
    printf( "'ULONG_MAX'             : %1lu \n", x1lu ); 
 
    x1lu++;                                     // checking wrap above MAX, 
    printf( "'x1lu++' wrap above MAX : %1lu \n", x1lu ); 
    printf( " \n" ); 
 
    printf( "cross check vs. long int: \n\n" ); 
 
    x1li = 1;                                   // simple case, 
    printf( "simple 'x1li = 1'       : %1ld \n", x1li );                // print the value, 
 
    x1li--;                                     // simple calculation, and checking 0, 
    printf( "'x1li--'                : %1ld \n", x1li ); 
 
    x1li--;                                     // simple calculation, and checking advance into negative, 
    printf( "'x1li--' advance to neg.: %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MIN;                                // checking INT_MIN, 
    printf( "'LONG_MIN'              : %1ld \n", x1li ); 
 
    x1li--;                                     // check wrap below MIN, 
    printf( "'x1li--' wrap below MIN : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    x1li = LONG_MAX;                                // checking INT_MAX, 
    printf( "'LONG_MAX'              : %1ld \n", x1li ); 
 
    x1li++;                                     // check wrap above MAX, 
    printf( "'x1li++' wrap above MAX : %1ld \n", x1li ); 
    printf( " \n" ); 
 
    printf( "cross check vs. unsigned int: \n\n" ); 
 
    x1u = 1;                                    // simple case, 
    printf( "simple 'x1u = 1'        : %1u \n", x1u );              // print the value, 
 
    x1u--;                                      // simple calculation, and checking 0, 
    printf( "'x1u--'                 : %1u \n", x1u ); 
 
    x1u--;                                      // simple calculation, and checking wrap below 0, 
    printf( "'x1u--' wrap below 0    : %1u \n", x1u ); 
    printf( " \n" ); 
 
    x1u = UINT_MAX;                                 // checking UINT_MAX, 
    printf( "'UINT_MAX'              : %1u \n", x1u ); 
 
    x1u++;                                      // checking wrap above MAX, 
    printf( "'x1u++' wrap above MAX  : %1u \n", x1u ); 
    printf( " \n" ); 
 
    printf( "cross check vs. int: \n\n" ); 
 
    x1i = 1;                                    // simple case, 
    printf( "simple 'x1i = 1'        : %1d \n", x1i );              // print the value, 
 
    x1i--;                                      // simple calculation, and checking 0, 
    printf( "'x1i--'                 : %1d \n", x1i ); 
 
    x1i--;                                      // simple calculation, and checking advance into negative, 
    printf( "'x1i--' advance to neg. : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MIN;                                  // checking INT_MIN, 
    printf( "'INT_MIN'               : %1d \n", x1i ); 
 
    x1i--;                                      // check wrap below MIN, 
    printf( "'x1i--' wrap below MIN  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    x1i = INT_MAX;                                  // checking INT_MAX, 
    printf( "'INT_MAX'               : %1d \n", x1i ); 
 
    x1i++;                                      // check wrap above MAX, 
    printf( "'x1i++' wrap above MAX  : %1d \n", x1i ); 
    printf( " \n" ); 
 
    printf( "Check arbitrary values from command line argument: \n\n", x1li ); 
 
    x1llu = strtou128( argv[ 1 ] ); 
    printf( "input as uint128        : %s \n", u128tostr( x1llu ) ); 
    printf( "under- / overflow error < 0 and > U128_MAX, \n\n" ); 
 
    printf( "performance of uint128: \n" ); 
    TIMEITcllu( x1llu = strtou128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = u128tostr( x1llu ), count, "" ); 
    printf( " \n" ); 
 
    x1lli = strtoi128( argv[ 1 ] ); 
    printf( "input as int128         : %s \n", i128tostr( x1lli ) ); 
    printf( "under- / overflow error < I128_MIN and > I128_MAX \n\n" ); 
 
    printf( "performance of int128: \n" ); 
    TIMEITclli( x1lli = strtoi128( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( str1 = i128tostr( x1lli ), count, "" ); 
    printf( " \n" ); 
 
    x1lu = strtoul( argv[ 1 ], NULL, 10 ); 
    printf( "input as unsig. longint : %1lu \n", x1lu ); 
    printf( "strtoul works up to ULONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to -ULONG_MAX, then stuck there, \n\n" ); 
 
    printf( "performance of ulong: \n\n" ); 
    TIMEITclu( x1lu = strtoul( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%lu", x1lu ), count, "" ); 
    printf( " \n" ); 
 
    x1li = strtol( argv[ 1 ], NULL, 10 ); 
    printf( "input as long int       : %1ld \n", x1li ); 
    printf( "strtol works up to LONG_MAX, then stuck, \n" ); 
    printf( "in negative wraps down to LONG_MIN, then stuck there, \n\n" ); 
 
    printf( "performance of long: \n\n" ); 
    TIMEITcli( x1li = strtol( argv[ 1 ], NULL, 10 ), count, "" ); 
    TIMEITcstr( snprintf( str1, 21, "%ld", x1li ), count, "" ); 
    printf( " \n" ); 
 
    x1u = atoi( argv[ 1 ] ); 
    printf( "input as uint           : %1u \n", x1u ); 
    printf( "atoi ( found no atou ) wrapping up to LONG_MAX, then stuck at \n" ); 
    printf( "4294967295 ( UINT_MAX ), in negative it wraps down to \n" ); 
    printf( "LONG-MIN, then stuck at 0. \n\n" ); 
 
    printf( "performance of uint: \n\n" ); 
    TIMEITcu( x1u = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 11, "%u", x1u ), count, "" ); 
    printf( " \n" ); 
 
    x1i = atoi( argv[ 1 ] ); 
    printf( "input as int            : %1d \n", x1i ); 
    printf( "atoi wraps up to LONG_MAX, then stuck at -1 \n" ); 
    printf( "in negative it wraps down to LONG_MIN, then stuck at 0. \n\n" ); 

    printf( "performance of atoi: \n\n" ); 
    TIMEITci( x1i = atoi( argv[ 1 ] ), count, "" ); 
    TIMEITcstr( snprintf( str1, 12, "%d", x1i ), count, "" ); 
    printf( " \n" ); 
 
// acc. anonchatGPT compiling with '-std=c99 helps to use wchar.h types ... not yet got it to work ... 
///     wide_str = \0; 
///     x1llu = wcstoull( argv[ 1 ], wide_str, 10 ); 
///     u128tostr( str, x1llu ); 
///     printf( "input as uint128        : %s \n", str ); 
 
    printf( "done \n \n" ); 
 
    return 0; 
} 

re-check appreciated.
[/edit ]

deleted 41 characters in body
Source Link
toolic
  • 16.4k
  • 6
  • 29
  • 221

I feel honoured by your effordeffort, esp. as none said 'doesn't work', 'bullshit' or 'superfluous', thus I - think to - have met a point that could like some care for.

< It's a try to keep code - left - and comments - right - separated and
a: keep comments near point,
b: keep code readable,
c: fight the missing back referencing which header covers which function. From a newbie POV 'including' sh/could be handeledhandled automatically rather then user nagging, with exception where pro's need alternative libraries.

Comment / corrections appreciated, again many thanks for all those hints!.

I feel honoured by your efford, esp. as none said 'doesn't work', 'bullshit' or 'superfluous', thus I - think to - have met a point that could like some care for.

< It's a try to keep code - left - and comments - right - separated and
a: keep comments near point,
b: keep code readable,
c: fight the missing back referencing which header covers which function. From a newbie POV 'including' sh/could be handeled automatically rather then user nagging, with exception where pro's need alternative libraries.

Comment / corrections appreciated, again many thanks for all those hints!

I feel honoured by your effort, esp. as none said 'doesn't work', 'bullshit' or 'superfluous', thus I - think to - have met a point that could like some care for.

< It's a try to keep code - left - and comments - right - separated and
a: keep comments near point,
b: keep code readable,
c: fight the missing back referencing which header covers which function. From a newbie POV 'including' sh/could be handled automatically rather then user nagging, with exception where pro's need alternative libraries.

Comment / corrections appreciated.

Source Link
Loading