I understand that register_printf_specifier is now deprecated.
I can no longer run code using register_printf_specifier using the C99 compiler at www.onlinegdb.com.
e.g. I really wanted to run the following code that adds the %B format specifier to printf() in order to print out integers in binary (from Is there a printf converter to print in binary format?):
/*
* File: main.c
* Author: Techplex.Engineer
*
* Created on February 14, 2012, 9:16 PM
*/
#include <stdio.h>
#include <stdlib.h>
#include <printf.h>
#include <math.h>
#include <string.h>
#include <stdarg.h>
static int printf_arginfo_M(const struct printf_info *info, size_t n, int *argtypes)
{
/* "%M" always takes one argument, a pointer to uint8_t[6]. */
if (n > 0) {
argtypes[0] = PA_POINTER;
}
return 1;
}
static int printf_output_M(FILE *stream, const struct printf_info *info, const void *const *args)
{
int value = 0;
int len;
value = *(int *) (args[0]);
// Beginning of my code ------------------------------------------------------------
//char buffer [50] = ""; // Is this bad?
char* buffer = (char*) malloc(sizeof(char) * 50);
// char buffer2 [50] = ""; // Is this bad?
char* buffer2 = (char*) malloc(sizeof(char) * 50);
int bits = info->width;
if (bits <= 0)
bits = 8; // Default to 8 bits
int mask = pow(2, bits - 1);
while (mask > 0) {
sprintf(buffer, "%s", ((value & mask) > 0 ? "1" : "0"));
strcat(buffer2, buffer);
mask >>= 1;
}
strcat(buffer2, "\n");
// End of my code --------------------------------------------------------------
len = fprintf(stream, "%s", buffer2);
free (buffer);
free (buffer2);
return len;
}
int main(int argc, char** argv)
{
register_printf_specifier('B', printf_output_M, printf_arginfo_M);
printf("%4B\n", 65);
return EXIT_SUCCESS;
}
When I do, I get:
main.c:65:53: warning: passing argument 3 of ‘register_printf_specifier’ from incompatible pointer type [-Wincompatible-pointer-types]
register_printf_specifier('B', printf_output_M, printf_arginfo_M);
^~~~~~~~~~~~~~~~
In file included from main.c:18:0:
/usr/include/printf.h:96:12: note: expected ‘int (*)(const struct printf_info *, size_t, int *, int *) {aka int (*)(const struct printf_info *, long unsigned int, int *, int *)}’ but argument is of type ‘int (*)(const struct printf_info *, size_t, int *) {aka int (*)(const struct printf_info *, long unsigned int, int *)}’
extern int register_printf_specifier (int __spec, printf_function __func,
^~~~~~~~~~~~~~~~~~~~~~~~~
main.c:67:15: warning: unknown conversion type character ‘B’ in format [-Wformat=]
printf("%4B\n", 65);
^
main.c:67:12: warning: too many arguments for format [-Wformat-extra-args]
printf("%4B\n", 65);
^~~~~~~
000
Since register_printf_specifier is now deprecated, what are programmers supposed to use instead? Create one's own variadic printf() like function?
P.S. Below is the updated code that corrects the errors pointed out to me. Make sure you use the right format specifier for the type of integer that you want to display in binary. (e.g. %hhB for chars and %hB for shorts). You can pad with spaces or zeros (e.g. %018hB will add 2 leading zeros to the binary since the size of shorts is 16 bits on the computer I am using). Please note: Make sure you use the right format specifier! If you do not, the binary output will likely be wrong especially for negative integers or unsigned integers.
/*
* File: main.c
* Author: Techplex.Engineer
* Modified by: Robert Kennedy
*
* Created on February 14, 2012, 9:16 PM
* Modified on August 28, 2021, 9:06 AM
*/
//
// The following #pragma's are the only way to supress the compiler warnings
// because there is no way of letting -Wformat know about the
// custom %B format specifier.
//
#pragma GCC diagnostic ignored "-Wformat="
#pragma GCC diagnostic ignored "-Wformat-extra-args"
#include <stdio.h> // Needed for fprintf(); sprintf() and printf();
#include <stdlib.h> // Needed for exit(); malloc(); and free(); and
// EXIT_SUCCESS macro constant.
#include <printf.h> // Needed for register_printf_specifier(); and related
// data structures (like "const struct print_info") and
// related macro constants (e.g. PA_POINTER)
#include <math.h> // Needed for pow(); and powl();
#include <string.h> // Needed for strcat; strncat; memset();
#include <limits.h> // Needed for min and max values for the various integer
// data types.
#include <inttypes.h> // Needed for int64_t data types and the min and max
// values.
static int printf_arginfo_B(const struct printf_info *info, size_t n, int *argtypes, int* size)
{
if (info->is_long_double)
*size = sizeof(long long); /* Optional to specify *size here */
else if (info->is_long)
*size = sizeof(long); /* Optional to specify *size here */
else
*size = sizeof(int); /* Optional to specify *size here */
if (n > 0) /* means there are arguments! */
{
argtypes[0] = PA_POINTER; /* Specifies a void* pointer type */
}
return 1;
}
static int printf_output_B(FILE *stream, const struct printf_info *info, const void *const *args)
{
const int sizeOfByte = CHAR_BIT;
const int charSizeInBits = sizeof(char) * sizeOfByte;
const int shortSizeInBits = sizeof(short) * sizeOfByte;
const int intSizeInBits = sizeof(int) * sizeOfByte;
const int longSizeInBits = sizeof(long) * sizeOfByte;
const int longlongSizeInBits = sizeof(long long) * sizeOfByte;
unsigned int intValue = 0;
unsigned long longValue = 0l;
unsigned long long longlongValue = 0ll;
int len; // Length of the string (containing the binary
// number) that was printed.
// On error, a negative number will be returned.
int i; // A simple counter variable.
int displayBits; // Number of bits to be displayed
// If greater than calcBits, leading zeros
// will be displayed.
int calcBits; // The minimum number of bits needed for the
// decimcal to binary conversion.
displayBits = info->width;
wchar_t padWithZero = info->pad;
char padChar = ' ';
if (info->is_long_double)
{
calcBits = longlongSizeInBits;
if (displayBits < longlongSizeInBits)
{
displayBits = longlongSizeInBits;
}
}
if (info->is_long)
{
calcBits = longSizeInBits;
if (displayBits < longSizeInBits)
{
displayBits = longSizeInBits;
}
}
if ( !(info->is_long) && !(info->is_long_double) && !(info->is_short) && !(info->is_char) )
{
calcBits = intSizeInBits;
if (displayBits < intSizeInBits)
{
displayBits = intSizeInBits;
}
}
if (info->is_short)
{
calcBits = shortSizeInBits;
if (displayBits < shortSizeInBits)
{
displayBits = shortSizeInBits;
}
}
if (info->is_char)
{
calcBits = charSizeInBits;
if (displayBits < charSizeInBits)
{
displayBits = charSizeInBits;
}
}
// printf("\ndisplayBits = %d and calcBits = %d\n", displayBits, calcBits);
char* buffer = (char*) malloc(sizeof(char) * (displayBits+1));
char* buffer2 = (char*) malloc(sizeof(char) * (displayBits+1));
if ( info->is_long_double )
{
longlongValue= * ((unsigned long long *) (args[0]));
unsigned long long mask = powl(2, calcBits - 1);
while (mask > 0)
{
sprintf(buffer, "%s", ((longlongValue & mask) > 0 ? "1" : "0"));
// strcat(buffer2, buffer);
strncat(buffer2, buffer, displayBits-( (int)strlen(buffer2)) );
mask >>= 1;
}
}
else if ( info->is_long )
{
longValue= * ((unsigned long *) (args[0]));
unsigned long mask = powl(2, calcBits - 1);
while (mask > 0)
{
sprintf(buffer, "%s", ((longValue & mask) > 0 ? "1" : "0"));
// strcat(buffer2, buffer);
strncat(buffer2, buffer, displayBits-( (int)strlen(buffer2)) );
mask >>= 1;
}
}
else
{
intValue = * ((unsigned int *) (args[0]));
unsigned long mask = pow(2, calcBits - 1);
while (mask > 0) {
sprintf(buffer, "%s", ((intValue & mask) > 0 ? "1" : "0"));
// strcat(buffer2, buffer);
strncat(buffer2, buffer, displayBits-( (int)strlen(buffer2)) );
mask >>= 1;
}
}
strcat(buffer2, "\0");
if (displayBits > calcBits)
{
if ('0' == padWithZero)
padChar = '0';
else
padChar = ' ';
memset(buffer, '\0', displayBits);
memset(buffer, padChar, (displayBits-calcBits));
strncat(buffer, buffer2, displayBits-( (int)strlen(buffer)) );
len = fprintf(stream, "%s", buffer);
}
else
{
len = fprintf(stream, "%s", buffer2);
}
free (buffer);
free (buffer2);
return len;
}
int main(int argc, char** argv)
{
const int sizeOfByte = 8;
register_printf_specifier('B', printf_output_B, printf_arginfo_B);
printf("Sizeof(char) is: %ld bits\n", sizeof(char) * sizeOfByte);
printf("CHAR_MAX %hhd in binary is: %hhB\n", CHAR_MAX, CHAR_MAX);
printf("CHAR_MIN %hhd in binary is: %hhB\n", CHAR_MIN, CHAR_MIN);
printf("UCHAR_MAX %hhu (unsigned) in binary is: %hhB\n", UCHAR_MAX, UCHAR_MAX);
printf("%hhd in binary is: %hhB\n", -5, -5);
printf(" %hhd in binary is: %hhB\n\n", 0, 0);
printf("Sizeof(short) is: %ld bits\n", sizeof(short) * sizeOfByte);
printf("SHRT_MAX %hd in binary is: %hB\n", SHRT_MAX, SHRT_MAX);
printf("SHRT_MIN %hd in binary is: %hB\n", SHRT_MIN, SHRT_MIN);
printf("USHRT_MAX %hu (unsigned) in binary is: %hB\n", USHRT_MAX, USHRT_MAX);
printf("USHRT_MAX %hu (unsigned) in binary with 2 leading zeros is: %018hB\n", USHRT_MAX, USHRT_MAX);
printf("USHRT_MAX %hu (unsigned) in binary with 2 leading spaces is: %18hB\n\n", USHRT_MAX, USHRT_MAX);
printf("Sizeof(int) is: %ld bits\n", sizeof(int) * sizeOfByte);
printf("INT_MAX %d in binary is: %B\n", INT_MAX, INT_MAX);
printf("INT_MIN %d in binary is: %B\n", INT_MIN, INT_MIN);
printf("UINT_MAX %u (unsigned) in binary is: %B\n", UINT_MAX, UINT_MAX);
printf("UINT_MAX %u (unsigned) in binary with 4 leading zeros is: %036B\n\n", UINT_MAX, UINT_MAX);
printf("Sizeof(long) is: %ld bits\n", sizeof(long) * sizeOfByte);
printf("LONG_MAX %ld in binary is: %lB\n", LONG_MAX, LONG_MAX);
printf("LONG_MIN %ld in binary is: %lB\n", LONG_MIN, LONG_MIN);
printf("ULONG_MAX %lu (unsigned) in binary is: %lB\n\n", ULONG_MAX, ULONG_MAX);
printf("Sizeof(long long) is: %ld bits\n", sizeof(long long) * sizeOfByte);
printf("LLONG_MAX %lld in binary is: %llB\n", LLONG_MAX, LLONG_MAX);
printf("LLONG_MIN %ld in binary is: %lB\n", LLONG_MIN, LLONG_MIN);
printf("ULLONG_MAX %llu (unsigned) in binary is: %llB\n\n", ULLONG_MAX, ULLONG_MAX);
printf("Sizeof(int64_t) is: %ld bits\n", sizeof(int64_t) * sizeOfByte);
printf("INT_64_MAX %lld in binary is: %LB\n", INT64_MAX, INT64_MAX);
printf("INT_64_MIN %lld in binary is: %LB\n", INT64_MIN, INT64_MIN);
printf("UINT64_MAX %llu in binary is: %LB\n", UINT64_MAX, UINT64_MAX);
return EXIT_SUCCESS;
}
Below is the output:
Sizeof(char) is: 8 bits
CHAR_MAX 127 in binary is: 01111111
CHAR_MIN -128 in binary is: 10000000
UCHAR_MAX 255 (unsigned) in binary is: 11111111
-5 in binary is: 11111011
0 in binary is: 00000000
Sizeof(short) is: 16 bits
SHRT_MAX 32767 in binary is: 0111111111111111
SHRT_MIN -32768 in binary is: 1000000000000000
USHRT_MAX 65535 (unsigned) in binary is: 1111111111111111
USHRT_MAX 65535 (unsigned) in binary with 2 leading zeros is: 001111111111111111
USHRT_MAX 65535 (unsigned) in binary with 2 leading spaces is: 1111111111111111
Sizeof(int) is: 32 bits
INT_MAX 2147483647 in binary is: 01111111111111111111111111111111
INT_MIN -2147483648 in binary is: 10000000000000000000000000000000
UINT_MAX 4294967295 (unsigned) in binary is: 11111111111111111111111111111111
UINT_MAX 4294967295 (unsigned) in binary with 4 leading zeros is: 000011111111111111111111111111111111
Sizeof(long) is: 64 bits
LONG_MAX 9223372036854775807 in binary is: 0111111111111111111111111111111111111111111111111111111111111111
LONG_MIN -9223372036854775808 in binary is: 1000000000000000000000000000000000000000000000000000000000000000
ULONG_MAX 18446744073709551615 (unsigned) in binary is: 1111111111111111111111111111111111111111111111111111111111111111
Sizeof(long long) is: 64 bits
LLONG_MAX 9223372036854775807 in binary is: 0111111111111111111111111111111111111111111111111111111111111111
LLONG_MIN -9223372036854775808 in binary is: 1000000000000000000000000000000000000000000000000000000000000000
ULLONG_MAX 18446744073709551615 (unsigned) in binary is: 1111111111111111111111111111111111111111111111111111111111111111
Sizeof(int64_t) is: 64 bits
INT_64_MAX 9223372036854775807 in binary is: 0111111111111111111111111111111111111111111111111111111111111111
INT_64_MIN -9223372036854775808 in binary is: 1000000000000000000000000000000000000000000000000000000000000000
UINT64_MAX 18446744073709551615 in binary is: 1111111111111111111111111111111111111111111111111111111111111111