处理INT_MIN和LONG_MIN时如何处理void*转换?

问题描述 投票:0回答:1

我正在尝试编写一个能够使用

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
c hex
1个回答
0
投票
  • 您使用的是小端机器,因此 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
© www.soinside.com 2019 - 2024. All rights reserved.