澄清C中的函数指针

以下代码来自不安全编程的示例abo3.c – 另请参阅为什么将extern puts put 转换为函数指针(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*并且不返回任何内容。


好吧,那段代码很糟糕 :

  1. main的前两个参数的传统命名是相反的:

     int main(int argv,char **argc) 
  2. 声明标准库函数system并使用“implicit int”作为int 。 这甚至不是错误的函数类型,而是数据类型!

     extern system,puts; 
  3. 将符号地址转换为函数指针几乎是理智的。 现在,如果它只是正确的类型…无论如何,在数据指针和代码指针大小相同的盒子上,它可能不会丢失任何信息。

     void (*fn)(char*)=(void(*)(char*))&system; // <== fn=(void(*)(char*))&puts; 
  4. 检查argv [!]是否至少为2应该不会在这里省略:

     strcpy(buf,argc[1]); 
  5. 通过错误类型的函数指针调用函数是UB。 不要那样做。 此外,在此点之前检查argv [!]是否至少为3 不是可选的。 FN(的argc [2]);

  6. 依赖strcpyexit隐式声明也很糟糕。 两者都没有与之相符的原型! (他们不返回int

它将变量fn声明为函数指针(对于具有char *类型的一个参数且不返回任何内容的函数( void )。

此变量使用system地址初始化 – 请参阅http://linux.die.net/man/3/system 。 如本页所述,这将需要演员表

那么,也许这只是一个带括号的游戏,其中void * fn(char *)是一个函数的声明,这个函数正在引用系统,我想

void (*fn)(char *)不是函数,它是函数指针。 您可以在这里参考以了解函数指针。 。 而且()在这里做的事你不能忽视它们。

但为什么参数(char *)没有名字? 这是允许的吗?

是的,允许这样做。 它的名字并不重要,但它的类型是。

它是纯函数的简单指针,它被赋予system调用的地址

首先,您要解决向system声明函数指针的麻烦。

然后通过重新定义它指向puts将它全部抛弃。

然后看起来你试图索引一个int ,但你已经颠倒了main的常用命名约定,即

 int main (int argc, char **argv) 

该行声明一个函数指针的变量,该函数指针接受一个参数并且不返回任何内容(void),这需要与同一函数原型的类型转换一样,外部函数的类型类似于void *指针,它们不是编译期间的早期绑定。

它是一个指向Function的指针。 让我告诉你,如果你试图在C中创建一个将使用文本菜单的应用程序而不是开关我会使用指向函数的指针:

 #include  #include 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 ); } 

编译并尝试。