我正在尝试编写一个能够使用
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
您使用的是小端机器,因此 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>
#define STDOUT 1
static const char *hex_syms = "0123456789abcdef";
static void write_hex_reversed( size_t n, void *buffer ) {
unsigned char *p = (unsigned char *)buffer + n;
for ( size_t i = 0; i < n; ++i ) {
--p;
write( STDOUT, hex_syms + ( *p / 16 ), 1 );
write( STDOUT, hex_syms + ( *p % 16 ), 1 );
}
}
static void handle_pointer( va_list argp ) {
void *p = va_arg( argp, void* );
write( STDOUT, "0x", 2 );
write_hex_reversed( sizeof( p ), &p ); // This is a LE machine.
}
// `n` takes place of the format string in this simpler code.
static void my_formatted_write( size_t n, ... ) {
va_list argp;
va_start( argp, n );
for ( size_t i = 0; i < n; ++i ) {
if ( i ) write( STDOUT, " ", 1 );
handle_pointer( argp );
}
va_end( argp );
}
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???
my_formatted_write( 2, int_min_as_ptr, int_max_as_ptr );
write( STDOUT, "\n", 1 );
}
输出:
0x0000000080000000 0x000000007fffffff
已知错误:
write
不保证写入请求的字节数。当第三个参数不为 1 时,需要在循环中调用它。不过,建立一个缓冲区可能比执行所有这些写入更好。write
的成功。va_list argp
作为参数是否保证有效,因为您希望调用者中的变量发生变化。应该是va_list *argpp
。