需要函数指针参数 ignored/not
Function pointer arguments ignored/not needed
我目前正在为微处理器编写 C 代码,但遇到了一些我无法解释的问题。我已经使用函数指针实现了一个命令行界面。为此,我制作了一个结构,其中包含命令名称、指向函数的指针 运行 以及帮助说明。
typedef void(*command)(char *);
typedef struct commandStruct {
char const *name;
command execute;
char const *help;
} commandStruct;
const commandStruct commands[] =
{
{"led", CmdLed, "Turns on or off the LED1"},
{"AT+START_SIM", start_simulation, "Starts the simulation"},
{"AT+STOP_SIM", stop_simulation, "Stops the simulation"},
{"",0,""} //End of table indicator.
};
void exec_command(char *buffer)
{
uint16 i = 0;
char *cmd = buffer;
char *args;
while (buffer[i])
{
if(buffer[i] == '=')
{
buffer[i] = 0;
args = buffer + i + 1;
break;
}
i++;
}
uint16 cmdCount = 0;
while(strcmp(commands[cmdCount].name,""))
{
if(!strcmp(commands[cmdCount].name,cmd))
{
commands[cmdCount].execute(args);
break;
}
cmdCount++;
}
}
void start_simulation(void) {run = 1;}
void stop_simulation(void) {run = 0;}
void CmdLed(char *args)
{
P1DIR |= BIT0;
if(!strcmp(args,"on")) P1OUT = 1;
if(!strcmp(args,"off")) P1OUT = 0;
}
我在函数 exec_command
上面包含了函数指针,这是使用函数指针的地方。在底部,我还放置了 start_simulation
和 stop_simulation
函数,以及 CmdLed
。我之前写了CmdLed
然后回来写了start_simulation
和stop_simulation
。我忘记了我已经将我的函数指针定义为以 (char *)
作为参数。然而,我惊讶地发现一切仍然编译并且 运行 绝对没问题。为什么是这样?似乎任何参数都只是 'dumped' 而未使用。
这不应该用现代编译器编译。
这里发生了什么:
start_simulation
将使用 char*
参数调用,但由于 start_simulation
没有参数,该参数将被简单地忽略(或 "dumped" 如您所写)。
请记住,在 C 函数中,参数被压入堆栈,调用者在调用后清理堆栈。所以如果你调用一个没有参数的函数假装它有参数,那么
- 调用者将参数压入堆栈
- 调用者调用了无参数函数
- 该函数忽略了堆栈上的参数
- 函数returns给调用者
- 调用方清理堆栈
也看看 this SO question。
我假设您在使用它们之前已经声明了您的函数,或者您的编译器将它们隐式声明为(C 默认值):
int start_simulation();
...
意思是 start_simulation
应该在其他地方定义为一个接受任何参数和 returning 一个 int 的函数。
但这至少应该给你一些警告,因为定义与声明不同,或者函数声明与 commandstruct 的第二个元素的命令声明不匹配(在 const commandStruct commands[] = ...
)
由于编译运行良好,cdecl的传参方式如下:
- 参数以相反的顺序入栈
- 被调用者被调用(return调用者的地址被压入堆栈)
- 被调用者可以从堆栈指针 + return 地址的大小开始获取其参数,但永远不会将它们从堆栈中删除
- 被叫方returns
- 调用者删除它推送到堆栈的参数(它知道它们)
这意味着您始终可以添加未使用的参数,前提是编译器具有足够的容忍度来编译不正确的调用,或者函数是使用空参数列表声明的。
我目前正在为微处理器编写 C 代码,但遇到了一些我无法解释的问题。我已经使用函数指针实现了一个命令行界面。为此,我制作了一个结构,其中包含命令名称、指向函数的指针 运行 以及帮助说明。
typedef void(*command)(char *);
typedef struct commandStruct {
char const *name;
command execute;
char const *help;
} commandStruct;
const commandStruct commands[] =
{
{"led", CmdLed, "Turns on or off the LED1"},
{"AT+START_SIM", start_simulation, "Starts the simulation"},
{"AT+STOP_SIM", stop_simulation, "Stops the simulation"},
{"",0,""} //End of table indicator.
};
void exec_command(char *buffer)
{
uint16 i = 0;
char *cmd = buffer;
char *args;
while (buffer[i])
{
if(buffer[i] == '=')
{
buffer[i] = 0;
args = buffer + i + 1;
break;
}
i++;
}
uint16 cmdCount = 0;
while(strcmp(commands[cmdCount].name,""))
{
if(!strcmp(commands[cmdCount].name,cmd))
{
commands[cmdCount].execute(args);
break;
}
cmdCount++;
}
}
void start_simulation(void) {run = 1;}
void stop_simulation(void) {run = 0;}
void CmdLed(char *args)
{
P1DIR |= BIT0;
if(!strcmp(args,"on")) P1OUT = 1;
if(!strcmp(args,"off")) P1OUT = 0;
}
我在函数 exec_command
上面包含了函数指针,这是使用函数指针的地方。在底部,我还放置了 start_simulation
和 stop_simulation
函数,以及 CmdLed
。我之前写了CmdLed
然后回来写了start_simulation
和stop_simulation
。我忘记了我已经将我的函数指针定义为以 (char *)
作为参数。然而,我惊讶地发现一切仍然编译并且 运行 绝对没问题。为什么是这样?似乎任何参数都只是 'dumped' 而未使用。
这不应该用现代编译器编译。
这里发生了什么:
start_simulation
将使用 char*
参数调用,但由于 start_simulation
没有参数,该参数将被简单地忽略(或 "dumped" 如您所写)。
请记住,在 C 函数中,参数被压入堆栈,调用者在调用后清理堆栈。所以如果你调用一个没有参数的函数假装它有参数,那么
- 调用者将参数压入堆栈
- 调用者调用了无参数函数
- 该函数忽略了堆栈上的参数
- 函数returns给调用者
- 调用方清理堆栈
也看看 this SO question。
我假设您在使用它们之前已经声明了您的函数,或者您的编译器将它们隐式声明为(C 默认值):
int start_simulation();
...
意思是 start_simulation
应该在其他地方定义为一个接受任何参数和 returning 一个 int 的函数。
但这至少应该给你一些警告,因为定义与声明不同,或者函数声明与 commandstruct 的第二个元素的命令声明不匹配(在 const commandStruct commands[] = ...
)
由于编译运行良好,cdecl的传参方式如下:
- 参数以相反的顺序入栈
- 被调用者被调用(return调用者的地址被压入堆栈)
- 被调用者可以从堆栈指针 + return 地址的大小开始获取其参数,但永远不会将它们从堆栈中删除
- 被叫方returns
- 调用者删除它推送到堆栈的参数(它知道它们)
这意味着您始终可以添加未使用的参数,前提是编译器具有足够的容忍度来编译不正确的调用,或者函数是使用空参数列表声明的。