这个问题在这里已有答案:
以下代码来自abo3.c的示例Insecure Programming - 另请参阅Why cast extern puts
to a function pointer (void(*)(char*))&puts
?:
int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system; // <==
char buf[256];
fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}
特别是这一行:
void (*fn)(char*)=(void(*)(char*))&system;
我认为void (*fn)(char*)
听起来像一个lambda,但我知道它不是。然后,也许这只是一个括号的游戏,其中void *fn(char*)
是一个函数的声明,这个函数引用system
?但为什么(char*
参数没有名字?这是允许的吗?
void (*fn)(char*)=(void(*)(char*))&system;
该行采用错误声明的符号system
(应该是int(const char*)
,而不是隐式int
)的地址,将其转换为fn
的类型并初始化该新的局部变量。
类型是void(*)(char*)
或指向函数的指针接收单个char*
并且什么都不返回。
Well, that code is all kinds of bad:
main
的前两个参数的传统命名是相反的:
int main(int argv,char **argc)
system
s声明标准库函数puts
和int
。这甚至不是错误的函数类型,而是数据类型!
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system; // <==
fn=(void(*)(char*))&puts;
argv
[!]是否至少为2应该在此处不被忽略:
strcpy(buf,argc[1]);
argv
[!]是否至少为3不是可选的。 FN(的argc [2]);strcpy
和exit
的隐含声明也非常糟糕。两者都没有与之相符的原型! (他们不返回int
)它将变量fn
声明为函数指针(对于具有char *
类型的一个参数并且不返回任何内容的函数(void
)。
这个变量用system
的地址初始化 - 见http://linux.die.net/man/3/system。如本页所述,这将需要演员表
那么,也许这只是一个带括号的游戏,其中void * fn(char *)是一个函数的声明,这个函数正在引用系统,我想
void (*fn)(char *)
不是函数,它是函数指针。 You can refer here to learn about function pointers.。而()
在这里很重要,你不能忽视它们。
但为什么参数(char *)没有名字?这是允许的吗?
是的,允许这样做。它的名字并不重要,但它的类型是。
它是纯粹而简单的函数指针,它被赋予system
调用的地址
首先,你去解决一个指向system
的函数指针的麻烦。
然后你把它全部扔掉,重新定义它指向puts
。
然后你似乎尝试索引int
,但你已经改变了main
的通常命名约定,这是
int main (int argc, char **argv)
该行声明一个函数指针的变量,它接受一个参数并且不返回任何内容(void),这需要与同一函数原型的类型转换一样,外部函数的类型与void *指针类似,它们不是编译期间的早期绑定。
它是一个指向Function的指针。让我告诉你,如果你试图在C中创建一个将使用文本菜单的应用程序而不是开关我会使用指向函数的指针:
#include <stdio.h>
#include<unistd.h>
void clearScreen( const int x );
int exitMenu( void );
int mainMenu( void );
int updateSystem( void );
int installVlcFromPpa( void );
int installVlcFromSource( void );
int uninstallVLC( void );
int chooseOption( const int min, const int max );
void showMenu( const char *question, const char **options, int (**actions)( void ), const int length );
int installVLC( void );
int meniuVLC( void );
void startMenu( void );
int main( void ){
startMenu();
return 0;
}
void clearScreen( const int x ){
int i = 0;
for( ; i < x ; i++ ){
printf( "\n" );
}
}
int exitMenu( void ) {
clearScreen( 100 );
printf( "Exiting... Goodbye\n" );
sleep( 1 );
return 0;
}
int mainMenu( void ){
clearScreen( 100 );
printf( "\t\t\tMain Manu\n" );
return 0;
}
int updateSystem( void ) {
clearScreen( 100 );
printf( "System update...\n" );
sleep( 1 );
return 1;
}
int installVlcFromPpa( void ) {
clearScreen( 100 );
printf("Install VLC from PPA \n");
sleep( 1 );
return 0;
}
int installVlcFromSource( void ) {
clearScreen( 100 );
printf( "Install VLC from Source \n" );
sleep( 1 );
return 0;
}
int uninstallVLC( void ) {
clearScreen( 100 );
printf( "Uninstall VLC... \n" );
sleep( 1 );
return 1;
}
int chooseOption( const int min, const int max ){
int option,check;
char c;
do{
printf( "Choose an Option:\t" );
if( scanf( "%d%c", &option, &c ) == 0 || c != '\n' ){
while( ( check = getchar() ) != 0 && check != '\n' );
printf( "\tThe option has to be between %d and %d\n\n", min, max );
}else if( option < min || option > max ){
printf( "\tThe option has to be between %d and %d\n\n", min, max );
}else{
break;
}
}while( 1 );
return option;
}
void showMenu( const char *question, const char **options, int ( **actions )( void ), const int length) {
int choose = 0;
int repeat = 1;
int i;
int ( *act )( void );
do {
printf( "\n\t %s \n", question );
for( i = 0 ; i < length ; i++ ) {
printf( "%d. %s\n", (i+1), options[i] );
}
choose = chooseOption( 1,length );
printf( " \n" );
act = actions[ choose - 1 ];
repeat = act();
if( choose == 3 ){
repeat = 0;
}
}while( repeat == 1 );
}
int installVLC( void ) {
clearScreen( 100 );
const char *question = "Installing VLC from:";
const char *options[10] = { "PPA", "Source", "Back to VLC menu" };
int ( *actions[] )( void ) = { installVlcFromPpa, installVlcFromSource, mainMenu };
size_t len = sizeof(actions) / sizeof (actions[0]);
showMenu( question, options, actions, (int)len );
return 1;
}
int meniuVLC( void ) {
clearScreen( 100 );
const char *question = "VLC Options";
const char *options[10] = { "Install VLC.", "Uninstall VLC.", "Back to Menu." };
int ( *actions[] )( void ) = { installVLC, uninstallVLC, mainMenu };
size_t len = sizeof(actions) / sizeof (actions[0]);
showMenu( question, options, actions, (int)len );
return 1;
}
void startMenu( void ){
clearScreen( 100 );
const char *question = "Choose a Menu:";
const char *options[10] = { "Update system.", "Install VLC", "Quit" };
int ( *actions[] )( void ) = { updateSystem, meniuVLC, exitMenu };
size_t len = sizeof(actions) / sizeof (actions[0]);
showMenu( question, options, actions, (int)len );
}
编译并尝试。