El siguiente código proviene del ejemplo abo3.c de Progtwigción insegura . Consulte también ¿Por qué convertir las extern puts
a un puntero de función (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); }
Específicamente esta línea:
void (*fn)(char*)=(void(*)(char*))&system;
Creo que void (*fn)(char*)
suena como un lambda, pero sé que no lo es. Entonces, tal vez esto sea solo un juego con paréntesis, donde void *fn(char*)
es una statement de una función y esta función hace referencia al system
. Pero, ¿por qué el parámetro (char*
) no tiene nombre? ¿Está esto permitido?
void (*fn)(char*)=(void(*)(char*))&system;
Esa línea toma la dirección del system
símbolos mal declarado (debe ser int(const char*)
, no implícito int
), la convierte al tipo de fn
e inicializa esa nueva variable local.
El tipo es void(*)(char*)
o puntero para funcionar recibiendo un solo char*
y no devolviendo nada.
Bueno, ese código es todo tipo de mal :
La denominación tradicional de los dos primeros argumentos a main
se invierte:
int main(int argv,char **argc)
Declarar el system
funciones de biblioteca estándar y puts
usando “int implícito” como int
s. ¡Ni siquiera es el tipo de función incorrecto, sino un tipo de datos!
extern system,puts;
Convertir la dirección de los símbolos en un puntero de función es casi sensato. Ahora, si solo fuera del tipo correcto … De todos modos, en un cuadro con punteros de datos e indicadores de códigos del mismo tamaño, probablemente no se pierda ninguna información.
void (*fn)(char*)=(void(*)(char*))&system; // <== fn=(void(*)(char*))&puts;
La verificación de si argv
[!] Es al menos 2 no debería omitirse aquí:
strcpy(buf,argc[1]);
Llamar una función a través de un puntero de función de tipo incorrecto es UB. No hagas eso Además, verificar si argv
[!] Es al menos 3 antes de este punto no es opcional. fn (argc [2]);
Confiar en la statement implícita para strcpy
y exit
también es realmente malo. ¡Ninguno tiene un prototipo consistente con eso! (no vuelven int
)
Declara la variable fn
como un puntero de función (a una función que tiene un argumento de tipo char *
y no devuelve nada ( void
).
Esta variable se inicializa con la dirección del system
; consulte http://linux.die.net/man/3/system . Como se indica en esta página, esto requerirá el reparto como se indica.
Entonces, quizás esto sea solo un juego con paréntesis, donde void * fn (char *) es una statement de una función y esta función hace referencia al sistema, creo
void (*fn)(char *)
no es una función, es un puntero a función. Puede consultar aquí para aprender sobre punteros de función. . Y ()
importa aquí, no puedes ignorarlos.
¿Pero por qué el parámetro (char *) no tiene nombre? esto es permitido?
Sí, está permitido hacerlo. Su nombre no es tan importante pero su tipo es.
Es puro y simple puntero a la función, que se asigna la dirección a la llamada del system
Primero te metes en la molestia de declarar un puntero de función al system
.
Luego lo tiras todo al redefinirlo para que apunte a puts
.
Entonces parece que intenta indexar un int
, pero ha invertido la convención de nomenclatura habitual para main
, que es
int main (int argc, char **argv)
La línea está declarando una variable de un puntero de función que toma un parámetro y no devuelve nada (vacío), esto es necesario junto con el encasillado al mismo prototipo de función, ya que las funciones externas son similares en su tipo a un puntero void *, no son temprano encuadernado durante la comstackción
Es un puntero a la función. Déjame mostrarte si intentas crear una aplicación en C que use menús de texto donde en lugar de cambiar usaré el puntero a Función:
#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 ); }
Compílalo y pruébalo.