c - printf 是如何处理这个 char** 参数的?

标签 c string parsing reference printf

我正在用 C 语言编写一个汇编程序,并修复了解析器中的一个错误(请参阅下面的解析器函数定义和输入文件)。我的程序的输出是...

-bash-3.2$ ./a.out branch.asm out.obj
input file name = 'branch.asm'
output file name = 'out.obj'


Error, couldn't find an opcode in token sequence: '▒▒▒▒mul' 'r0' ...
-bash-3.2$

我意识到,当我将 char** pLabel 传递给 printf 时,我需要取消引用它。我不明白的是:即使我给了它一个错误的参数, printf 如何仍然能够打印字符串?如果它仍然能够找到该字符串,为什么要在它前面加上垃圾(我假设垃圾来自字符串地址值)?

如果您希望我提供更多信息,请告诉我。这只是一个大型程序,我不认为源代码的其余部分对于理解我的问题是必要的(实际上只是围绕 printf 如何处理字符串引用)。

输入文件如下...

        .ORIG x3000
LABEL1  AND R0,R0,#0
        ADD R0,R1,R2            ;
LABEL2  ADD R0,R0,#-1           ;
        BRP LABEL2
        BRNZ    label
        BRNZ    LABEL1
        BRNZP   LABEL1
        BR      LABEL1
LABEL   BRP     LABEL1
MUL     R0,R1,R2                ;
        .END

输入文件结尾 解析器定义开始...

/* Input: Assembly Program Input File
          Pointer to current assembly line
   Work:  attaches pointer vars to strings holding the
          LABEL, Opcode, Arg1, Arg2, Arg3, and Arg4
   Ret:   EMPTY_LINE,   (Line was empty)
          OK,           (Line is now parsed)
          DONE          (No more lines in File)
   Note:  Pseudo-ops are returned as Opcodes.
*/
int readAndParse( FILE * pInfile, char * pLine, char ** pLabel, char ** pOpcode,
                  char ** pArg1, char ** pArg2, char ** pArg3, char ** pArg4)
{
  char * lRet, * lPtr;
  int i;
  /* Pull line (INCLUDING \n) and return in pLine string */
  if( !fgets( pLine, MAX_LINE_LENGTH, pInfile ) )  return( DONE );

  for( i = 0; i < strlen( pLine ); i++ ) /* Convert entire line to lowercase  */
    pLine[i] = tolower( pLine[i] );

  *pLabel = *pOpcode = *pArg1 = *pArg2 = *pArg3 = *pArg4 = pLine + strlen(pLine); /* Point to '\0'! */

  /* ignore the assembly comments ... */
  lPtr = pLine;
  while( *lPtr != ';' && *lPtr != '\0' && *lPtr != '\n' )
    lPtr++; /* Find the 1st occurence of comment or a newline */

  *lPtr = '\0'; /* Chunck any comments or newlines. We only want relevant tokens. */

  /* Fetch first token in pLine delimted by \t \n (SPACE) or ,. strtok returns NULL when \0.
     Subsequent calls expect the a parameter of NULL & continue where it left off.
  */
  if( !(lPtr = strtok( pLine, "\t\n ," ) ) )  return( EMPTY_LINE );

  /* Logic to handle option of LABEL vs Opcode as starting token for line */
  if( isOpcode( lPtr ) == -1 && lPtr[0] != '.' ) /* found a label */
  {
    *pLabel = lPtr;
    if( !( lPtr = strtok( NULL, "\t\n ," ) ) ) return( OK );
  }
  *pOpcode = lPtr;
  if( isOpcode( *pOpcode ) == -1 && lPtr[0] != '.' )
    {
      printf("\nError, couldn't find an opcode in token sequence: '%s' '%s' ...\n", pLabel, *pOpcode);
      exit(2);
    }

  if( !( lPtr = strtok( NULL, "\t\n ," ) ) ) return( OK );
  *pArg1 = lPtr;

  if( !( lPtr = strtok( NULL, "\t\n ," ) ) ) return( OK );
  *pArg2 = lPtr;

  if( !( lPtr = strtok( NULL, "\t\n ," ) ) ) return( OK );
  *pArg3 = lPtr;

  if( !( lPtr = strtok( NULL, "\t\n ," ) ) ) return( OK );
  *pArg4 = lPtr;

  return( OK );
}

最佳答案

发生的事情如下:在内存布局中,*pLabel 后面是 pLine 指向的字符。 在对 printf 的调用中,pLabel 未取消引用,printf 在 pLabel 处找到四个非零字节并打印它们(这实际上是存储在 pLabel 中的地址)。因为 printf 没有看到终止空字符,所以它继续打印在 pLabel(即 pLine)后面找到的字节。 pLine 以 'mul' 开头,后跟 strtok 放在那里的\0。

关于c - printf 是如何处理这个 char** 参数的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28381301/

相关文章:

java - 如何使用 SAX 解析器解析 XML

python - 当用C扩展Python时,如何用C动态构建复杂的结构?

c - 在c中将int存储为字符串的有效方法

C -- 在没有 #include <stdio.h> 的情况下打印到屏幕?

c - 用字符串做数学?

java - 如何使用 Retrofit2 将 json 解析为具有子类的类

c - fscanf - 使用太长的字符串

python - 如何从 csv 文件自动获取标题

c - C 中的独立字符串操作变体

c# - `DateTime.Parse` 解析哪个时区的时间戳?