我的代码如下。
当我使用Visual Studio进行编译,调试和执行时,这是正确的。当我使用'gcc'进行编译时,这也是正确的,但是在Linux中执行时是错误的。运行时内存错误。
当打印'szBuf'时,错误是无法访问内存。
我想知道为什么在Windows中可以使用,但在Linux中不能使用?
#include <stdio.h>
void ItoA(int nNum, char *pStr);
void Print(const char *pFormat, ...);
int main()
{
char ch = 'a';
int nNum = 11;
char szBuf[255] = "";
Print("ch: %c\n", ch);
Print("n: %d\n", nNum);
Print("s: %s\n", szBuf);
return 0;
}
void ItoA(int nNum, char *pStr)
{
if (NULL != pStr)
{
char szNum[255] = "";
int i = 0;
for (i = 0; 0 != nNum; i++)
{
szNum[i] = nNum % 10 + '0';
nNum /= 10;
}
for (i = i - 1; i >= 0; i--, pStr++)
{
*pStr = szNum[i];
}
*pStr = '\0';
}
}
void Print(const char *pFormat, ...)
{
if (NULL != pFormat)
{
char *pTemp = (char *)&pFormat;
pTemp += 4;
while ('\0' != *pFormat)
{
if ('%' == *pFormat)
{
pFormat++;
switch (*pFormat)
{
case 'c':
{
putchar(*pTemp);
pTemp += 4;
}
break;
case 'd':
{
char szBuf[255] = "";
int nNum = 0;
ItoA(*(int *)pTemp, szBuf);
for (int i = 0; '\0' != szBuf[i]; i++)
{
putchar(szBuf[i]);
}
pTemp += 4;
}
break;
case 's':
{
for (int i = 0; '\0' != (*(char **)pTemp)[i]; i++)
{
putchar((*(char **)pTemp)[i]);
}
pTemp += 4;
}
break;
default:
{
pFormat--;
putchar(*pTemp);
}
break;
}
}
else
{
putchar(*pFormat);
}
pFormat++;
}
}
}
答案 0 :(得分:1)
这些行以及pTemp
周围的所有内容都有未定义的行为:
char *pTemp = (char *)&pFormat;
pTemp += 4;
您必须使用va_start
中的va_arg
和stdarg.h
来获得可变参数。 &pFormat
是Print
函数中局部变量的地址,与参数的传递方式无关。指向一个对象的指针的算术运算不能产生指向另一个对象的指针。
答案 1 :(得分:0)
虽然某些调用约定使用堆栈传递函数参数, 有些呼叫转化使用注册传递。
您的代码可以用于使用堆栈的调用约定,但不能用于使用寄存器的调用约定< / strong>。
看来,Visual Studio的默认值为x86编译(32位,通常使用堆栈),而gcc的默认值为64位编译(通常使用寄存器)。 >
您应该使用stdarg.h中的API从变量参数列表中获取值。