printf 是如何处理这个 char** 参数的?
How did printf handle this char** parameter?
我正在用 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 '[=12=]'! */
/* ignore the assembly comments ... */
lPtr = pLine;
while( *lPtr != ';' && *lPtr != '[=12=]' && *lPtr != '\n' )
lPtr++; /* Find the 1st occurence of comment or a newline */
*lPtr = '[=12=]'; /* 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 [=12=].
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 编写一个汇编程序并修复了我的解析器中的一个错误(请参阅下面的解析器函数定义和输入文件)。我程序的输出是...
-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 '[=12=]'! */
/* ignore the assembly comments ... */
lPtr = pLine;
while( *lPtr != ';' && *lPtr != '[=12=]' && *lPtr != '\n' )
lPtr++; /* Find the 1st occurence of comment or a newline */
*lPtr = '[=12=]'; /* 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 [=12=].
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。