register_printf_specifier 的替代方法(使用 printf() 以二进制格式打印数字)
Alternatives to register_printf_specifier ( to print numbers in binary format using printf() )
我知道 register_printf_specifier 现已弃用。
我无法再使用 register_printf_specifier 在 www.onlinegdb.com 上使用 C99 编译器 运行 代码。
例如我真的很想 运行 以下代码将 %B 格式说明符添加到 printf() 以便打印出二进制整数(来自 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;
}
当我这样做时,我得到:
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
由于 register_printf_specifier 现已弃用,程序员应该改用什么?创建自己的可变参数 printf() 之类的函数?
P.S。以下是更正向我指出的错误的更新代码。确保对要以二进制显示的整数类型使用正确的格式说明符。 (例如 %hhB 代表字符,%hB 代表短裤)。您可以用空格或零填充(例如,%018hB 将在二进制文件中添加 2 个前导零,因为在我使用的计算机上,短裤的大小是 16 位)。请注意:确保使用正确的格式说明符!如果不这样做,二进制输出可能会出错,尤其是对于负整数或无符号整数。
/*
* 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, "[=13=]");
if (displayBits > calcBits)
{
if ('0' == padWithZero)
padChar = '0';
else
padChar = ' ';
memset(buffer, '[=13=]', 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;
}
下面是输出:
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
register_printf_specifier
不 已弃用 - register_printf_function
已弃用。您的代码确实编译并且 运行 - 您可以看到它在最后打印二进制文件 - 您只是有一些编译器警告。如果您需要证明 register_printf_specifier
有效,请参阅 printf.h:
typedef int printf_arginfo_size_function (const struct printf_info *__info,
size_t __n, int *__argtypes,
int *__size);
/* Old version of 'printf_arginfo_function' without a SIZE parameter. */
typedef int printf_arginfo_function (const struct printf_info *__info,
size_t __n, int *__argtypes);
...
/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
specified to determine how many arguments a SPEC conversion requires and
what their types are. */
extern int register_printf_specifier (int __spec, printf_function __func,
printf_arginfo_size_function __arginfo)
__THROW;
/* Obsolete interface similar to register_printf_specifier. It can only
handle basic data types because the ARGINFO callback does not return
information on the size of the user-defined type. */
extern int register_printf_function (int __spec, printf_function __func,
printf_arginfo_function __arginfo)
__THROW __attribute_deprecated__;
即在现代代码中,您应该使用 register_printf_specifier
而不是 register_printf_function
。您会注意到它们的签名非常相似,唯一的区别是最后一个参数是 printf_arginfo_size_function
而不是 printf_arginfo_function
.
这就是您的问题 - 您将 printf_arginfo_function
类型的参数传递给需要 printf_arginfo_size_function
类型参数的函数。您需要将 int* size
参数添加到 printf_arginfo_M
并用参数的大小填充它 - 即 *size = sizeof(int)
.
顺便说一句,您可以从编译器警告中理解这一点:
/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 *)}’
至于你的修饰函数,考虑你的代码:
int bits = info->width;
if (bits <= 0)
bits = 8; // Default to 8 bits
int mask = pow(2, bits - 1);
考虑到您在这里遗漏了很多位 - 例如,对于 65,您需要 7 位,而当您打印“%4B”时,您只打印了底部的 4 位。
此外,如果您想以二进制形式打印 64 位数字,则与使用 %lld
打印 64 位整数的方式相同 - 您应该使用 %llB
打印数字。然后,在 printf_output_m
里面你可以这样写代码:
if (info->is_long_double) {
long_value = *(uint64_t*)(args[0]);
bits = 64;
}
请注意,这需要对您的函数进行总体重新设计 - 您必须将 maxBits
更改为 64(因为您希望支持最多 64 位的打印)等。
至于 main.c:67:15: warning: unknown conversion type character ‘B’ in format [-Wformat=]
警告 - 如果没有 manually suppressing the -Wformat
flag for your lines of code,这些警告是无法避免的。截至目前,无法让 -Wformat
知道您的自定义说明符。
不相关的旁注 - Google 的最新 CTF 有一个非常酷的挑战,涉及对使用 register_printf_function
编写的虚拟机进行逆向工程(是的,已弃用的那个) - 你可以看到源代码here.
我知道 register_printf_specifier 现已弃用。
我无法再使用 register_printf_specifier 在 www.onlinegdb.com 上使用 C99 编译器 运行 代码。
例如我真的很想 运行 以下代码将 %B 格式说明符添加到 printf() 以便打印出二进制整数(来自 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;
}
当我这样做时,我得到:
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
由于 register_printf_specifier 现已弃用,程序员应该改用什么?创建自己的可变参数 printf() 之类的函数?
P.S。以下是更正向我指出的错误的更新代码。确保对要以二进制显示的整数类型使用正确的格式说明符。 (例如 %hhB 代表字符,%hB 代表短裤)。您可以用空格或零填充(例如,%018hB 将在二进制文件中添加 2 个前导零,因为在我使用的计算机上,短裤的大小是 16 位)。请注意:确保使用正确的格式说明符!如果不这样做,二进制输出可能会出错,尤其是对于负整数或无符号整数。
/*
* 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, "[=13=]");
if (displayBits > calcBits)
{
if ('0' == padWithZero)
padChar = '0';
else
padChar = ' ';
memset(buffer, '[=13=]', 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;
}
下面是输出:
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
register_printf_specifier
不 已弃用 - register_printf_function
已弃用。您的代码确实编译并且 运行 - 您可以看到它在最后打印二进制文件 - 您只是有一些编译器警告。如果您需要证明 register_printf_specifier
有效,请参阅 printf.h:
typedef int printf_arginfo_size_function (const struct printf_info *__info,
size_t __n, int *__argtypes,
int *__size);
/* Old version of 'printf_arginfo_function' without a SIZE parameter. */
typedef int printf_arginfo_function (const struct printf_info *__info,
size_t __n, int *__argtypes);
...
/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
specified to determine how many arguments a SPEC conversion requires and
what their types are. */
extern int register_printf_specifier (int __spec, printf_function __func,
printf_arginfo_size_function __arginfo)
__THROW;
/* Obsolete interface similar to register_printf_specifier. It can only
handle basic data types because the ARGINFO callback does not return
information on the size of the user-defined type. */
extern int register_printf_function (int __spec, printf_function __func,
printf_arginfo_function __arginfo)
__THROW __attribute_deprecated__;
即在现代代码中,您应该使用 register_printf_specifier
而不是 register_printf_function
。您会注意到它们的签名非常相似,唯一的区别是最后一个参数是 printf_arginfo_size_function
而不是 printf_arginfo_function
.
这就是您的问题 - 您将 printf_arginfo_function
类型的参数传递给需要 printf_arginfo_size_function
类型参数的函数。您需要将 int* size
参数添加到 printf_arginfo_M
并用参数的大小填充它 - 即 *size = sizeof(int)
.
顺便说一句,您可以从编译器警告中理解这一点:
/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 *)}’
至于你的修饰函数,考虑你的代码:
int bits = info->width;
if (bits <= 0)
bits = 8; // Default to 8 bits
int mask = pow(2, bits - 1);
考虑到您在这里遗漏了很多位 - 例如,对于 65,您需要 7 位,而当您打印“%4B”时,您只打印了底部的 4 位。
此外,如果您想以二进制形式打印 64 位数字,则与使用 %lld
打印 64 位整数的方式相同 - 您应该使用 %llB
打印数字。然后,在 printf_output_m
里面你可以这样写代码:
if (info->is_long_double) {
long_value = *(uint64_t*)(args[0]);
bits = 64;
}
请注意,这需要对您的函数进行总体重新设计 - 您必须将 maxBits
更改为 64(因为您希望支持最多 64 位的打印)等。
至于 main.c:67:15: warning: unknown conversion type character ‘B’ in format [-Wformat=]
警告 - 如果没有 manually suppressing the -Wformat
flag for your lines of code,这些警告是无法避免的。截至目前,无法让 -Wformat
知道您的自定义说明符。
不相关的旁注 - Google 的最新 CTF 有一个非常酷的挑战,涉及对使用 register_printf_function
编写的虚拟机进行逆向工程(是的,已弃用的那个) - 你可以看到源代码here.