scanf寄存器新转换说明符

scanf寄存器新转换说明符,c,gcc,binary,scanf,glibc,C,Gcc,Binary,Scanf,Glibc,本周我为printf函数系列编写了一个扩展,以接受%b来打印二进制文件。为此,我使用了函数register\u printf\u specifier() 现在,我想知道是否可以在scanf函数族中执行相同的操作,以接受二进制输入并将其写入变量 是否有任何扩展允许我这样做?TL;DR:否。使用glibc时,至少否 我下载了最近的glibc版本: % wget https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.gz % tar -xzf glibc-2.29

本周我为
printf
函数系列编写了一个扩展,以接受
%b
来打印二进制文件。为此,我使用了函数
register\u printf\u specifier()

现在,我想知道是否可以在
scanf
函数族中执行相同的操作,以接受二进制输入并将其写入变量


是否有任何扩展允许我这样做?

TL;DR:否。使用
glibc
时,至少否


我下载了最近的
glibc
版本:

% wget https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.gz
% tar -xzf glibc-2.29.tar.gz
grep
'ed
find
,搜索我脑海中出现的随机
scanf
家庭函数-在这种情况下,是
vfscanf

% find | grep "vfscanf"
根据我的经验,我知道真正的实现在
-internal
中的某个地方,但我查看了输出:

./stdio-common/iovfscanf.c
./stdio-common/isoc99_vfscanf.c
./stdio-common/vfscanf-internal.c
./stdio-common/vfscanf.c
./sysdeps/ieee754/ldbl-opt/nldbl-iovfscanf.c
./sysdeps/ieee754/ldbl-opt/nldbl-isoc99_vfscanf.c
./sysdeps/ieee754/ldbl-opt/nldbl-vfscanf.c
并决定检查实际上包含内部函数存根的
/stdio common/vfscanf.c

% cat ./stdio-common/vfscanf.c

int
___vfscanf (FILE *s, const char *format, va_list argptr)
{
  return __vfscanf_internal (s, format, argptr, 0);
}
接下来,我浏览了文件,找到了格式分析器:

% cat ./stdio-common/vfscanf-internal.c | head -n 1390 | tail -n 20
          }
          break;

        case L_('x'):   /* Hexadecimal integer.  */
        case L_('X'):   /* Ditto.  */
          base = 16;
          goto number;

        case L_('o'):   /* Octal integer.  */
          base = 8;
          goto number;

        case L_('u'):   /* Unsigned decimal integer.  */
          base = 10;
          goto number;

        case L_('d'):   /* Signed decimal integer.  */
          base = 10;
          flags |= NUMBER_SIGNED;
          goto number;
我查看了文件的末尾,发现了一些整理案例标签:

% cat ./stdio-common/vfscanf-internal.c | tail -n 60
                  ++done;
                }
            }
          break;

        case L_('p'):   /* Generic pointer.  */
          base = 16;
          /* A PTR must be the same size as a `long int'.  */
          flags &= ~(SHORT|LONGDBL);
          if (need_long)
            flags |= LONG;
          flags |= READ_POINTER;
          goto number;

        default:
          /* If this is an unknown format character punt.  */
          conv_error ();
        }
    }

  /* The last thing we saw int the format string was a white space.
     Consume the last white spaces.  */
  if (skip_space)
    {
      do
        c = inchar ();
      while (ISSPACE (c));
      ungetc (c, s);
    }

 errout:
  /* Unlock stream.  */
  UNLOCK_STREAM (s);

  scratch_buffer_free (&charbuf.scratch);

  if (__glibc_unlikely (done == EOF))
    {
      if (__glibc_unlikely (ptrs_to_free != NULL))
        {
          struct ptrs_to_free *p = ptrs_to_free;
          while (p != NULL)
            {
              for (size_t cnt = 0; cnt < p->count; ++cnt)
                {
                  free (*p->ptrs[cnt]);
                  *p->ptrs[cnt] = NULL;
                }
              p = p->next;
              ptrs_to_free = p;
            }
        }
    }
  else if (__glibc_unlikely (strptr != NULL))
    {
      free (*strptr);
      *strptr = NULL;
    }
  return done;
}
%cat./stdio common/vfscanf internal.c | tail-n 60
++完成;
}
}
打破
大小写L_uP('p'):/*泛型指针*/
基数=16;
/*PTR的大小必须与“长整型”相同*/
标志&=~(SHORT | LONGDBL);
如果(需要长时间)
旗帜|=长;
标志|=读取指针;
转到号码;
违约:
/*如果这是一个未知格式的字符punt*/
conv_错误();
}
}
/*我们最后看到的格式字符串是一个空白。
消耗最后的空格*/
if(跳过空格)
{
做
c=英寸();
while(ISSPACE(c));
ungetc(c,s);
}
错误:
/*解锁流*/
解锁_流;
无刮擦缓冲区(&charbuf.scratch);
如果(不太可能(完成==EOF))
{
如果(uuu glibc_u不太可能(ptr_uto_ufree!=NULL))
{
结构ptrs_to_free*p=ptrs_to_free;
while(p!=NULL)
{
对于(大小cnt=0;cntcount;++cnt)
{
自由(*p->ptrs[cnt]);
*p->ptrs[cnt]=NULL;
}
p=p->next;
ptrs_至_free=p;
}
}
}
否则如果(uuu glibc_u不太可能(strprtr!=NULL))
{
免费(*strptr);
*strprpr=NULL;
}
已完成的返回;
}

以及完成函数的代码。这意味着,对于
scanf
-系列函数之一,所有格式说明符都是常量,这意味着您无法注册新的处理程序,而不影响glibc源代码中的大型clusterf..k(当然,这是不可移植的)。

您必须查看文档并找出答案。我甚至不知道您可以扩展
printf
,但显然GCC允许您。我查看了GCC文档,它看起来没有可自定义的输入,只有输出。@tadman有,非常好。如果您感兴趣:这是printfn中
%b
的代码请注意,是GNU C库()而不是GNU C编译器(
gcc
)允许您注册
printf()的扩展。此类功能通常不可用-您必须自己编写替换函数(可能使用不同但相关的名称,并且可能仅在必要时才将系统函数用于主要的grunt工作和您的扩展。我从这里了解到,bw
%I
%d
:)之间存在差异@Cacahuetferito不太可能,可能glibc有一点不同。在大多数情况下,这是不明显的。