我正在尝试编写一个能够使用
void*
函数打印 write
的函数。您可以在下面看到我的代码,适用于某些场景,但当我尝试使用 INT_MIN
、LONG_MIN
甚至 INT_MAX
等值时,它会失败。
static int write_hex(unsigned char *buffer, int i)
{
char tmp;
int leading_zero;
int counter;
leading_zero = 1;
counter = 0;
tmp = "0123456789abcdef"[buffer[i] / 16];
if (tmp != '0' || !leading_zero)
{
write(1, &tmp, 1);
leading_zero = 0;
counter++;
}
tmp = "0123456789abcdef"[buffer[i] % 16];
if (tmp != '0' || !leading_zero)
{
write(1, &tmp, 1);
leading_zero = 0;
counter++;
}
return (counter);
}
int handle_pointer(va_list args)
{
int i;
int counter;
void *ptr;
unsigned char *buffer;
ptr = va_arg(args, void*);
buffer = malloc(sizeof(ptr));
ft_memcpy(buffer, &ptr, sizeof(ptr));
i = 0;
write(1, "0x", 2);
counter = 2;
while (buffer[i])
{
counter += write_hex(buffer, i);
i++;
}
free(buffer);
return (counter);
}
测试失败的结果:
args: [" %p %p ", INT_MIN, INT_MAX]
printf: [ 0x80000000 0x7fffffff ] = 23
ft_printf: [ 0x 0xffffff7f ] = 15
您使用的是 LE 机器。所以 0x7FFFFFFF 被存储为 0xFF,FF,FF,7F。这就解释了
0xffffff7f
。
while (buffer[i])
没有任何意义,因为它会导致你在遇到0x00字节时停止打印,例如0x80000000的第一个字节。这就解释了0x
。这也意味着您可能会阅读超出预期的内容并导致未定义的行为。
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static const char *hex_syms = "0123456789abcdef";
#define STDOUT 1
static size_t write_hex_reversed( size_t n, void *buffer ) {
unsigned char *p = (unsigned char *)buffer + n;
for ( size_t i = 0; i < n; ++i ) {
--p;
{
char hex_sym = hex_syms[ *p / 16 ];
write( STDOUT, &hex_sym, 1 );
}
{
char hex_sym = hex_syms[ *p % 16 ];
write( STDOUT, &hex_sym, 1 );
}
}
return n * 2;
}
// `n` takes place of the format string in this simpler code.
static size_t handle_pointer( size_t n, ... ) {
va_list argp;
va_start( argp, n );
for ( size_t i = 0; i < n; ++i ) {
if ( i )
write( STDOUT, " 0x", 3 );
else
write( STDOUT, "0x", 2 );
void *p = va_arg( argp, void* );
write_hex_reversed( sizeof( p ), &p );
}
return n * ( 3 + sizeof( void * ) ) - 1;
}
int main( void ) {
void *int_min_as_ptr = (void*)(uintptr_t)(unsigned)INT_MIN; // Why???
void *int_max_as_ptr = (void*)(uintptr_t)(unsigned)INT_MAX; // Why???
handle_pointer( 2, int_min_as_ptr, int_max_as_ptr );
write( STDOUT, "\n", 1 );
}