澄清C中的函数指针[重复]

问题描述 投票:12回答:7

这个问题在这里已有答案:

以下代码来自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*参数没有名字?这是允许的吗?

c
7个回答
2
投票
void (*fn)(char*)=(void(*)(char*))&system;

该行采用错误声明的符号system(应该是int(const char*),而不是隐式int)的地址,将其转换为fn的类型并初始化该新的局部变量。 类型是void(*)(char*)或指向函数的指针接收单个char*并且什么都不返回。


Well, that code is all kinds of bad

  1. main的前两个参数的传统命名是相反的: int main(int argv,char **argc)
  2. 使用“implicit int”作为systems声明标准库函数putsint。这甚至不是错误的函数类型,而是数据类型! 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

8
投票

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

这个变量用system的地址初始化 - 见http://linux.die.net/man/3/system。如本页所述,这将需要演员表


4
投票

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

void (*fn)(char *)不是函数,它是函数指针。 You can refer here to learn about function pointers.。而()在这里很重要,你不能忽视它们。

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

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


3
投票

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


2
投票

首先,你去解决一个指向system的函数指针的麻烦。

然后你把它全部扔掉,重新定义它指向puts

然后你似乎尝试索引int,但你已经改变了main的通常命名约定,这是

int main (int argc, char **argv)

1
投票

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


1
投票

它是一个指向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 );
}

编译并尝试。

© www.soinside.com 2019 - 2024. All rights reserved.