2016-11-23 6 views
1

J'ai un code C qui ressemble essentiellement quelque chose commeObtenir l'adresse de retour d'une fonction en C

double* my_function(double* input) { 
    double* output = (double*) malloc(...); 
    // Do some stuff to output based on input 
    return output; 
} 

En supposant que je l'ai déjà construit un tableau appelé my_var_in, mon code principal a quelque chose comme

double* my_var_out = my_function(my_var_in); 

Cela crée nouvelle mémoire, qui my_var_out des points à; la plupart du temps, c'est exactement ce que je veux. Cependant, parfois je veux juste mettre à jour la mémoire déjà existante. Si j'écris

double* my_var = ... ; // allocate and fill my_var as desired 
my_var = my_function(my_var); 

Ensuite, je perds le pointeur vers la mémoire précédemment existant depuis my_var pointe désormais à la mémoire nouvellement allouée. J'ai joué avec plusieurs idées différentes pour contourner cela.

1) Je sais que je peux obtenir ce travail en changeant le style de fonction à quelque chose comme

void my_function(double* destination, double* source) { 
    // Check if destination == source and update based on this 

Je l'ai déjà développé avec ce style de passer le pointeur de destination comme argument d'entrée et la mise à jour là ; cela fonctionne très bien fonctionnellement, mais j'aime le style de sortie des pointeurs mieux et je veux continuer à développer avec elle.

2) Sur la base here et here, il semble que la __builtin_return_address fonction pourrait être d'une certaine utilité. Je pense que je peux utiliser cette fonction pour comparer l'adresse d'entrée avec l'adresse de sortie et allouer/mettre à jour en fonction de cela. Après avoir lu la documentation here, je l'ai écrit le test suivant

int* just_testing(int* in) { 
    void* ptr = __builtin_return_address(0); // the return address of just_testing 
    printf("Input address: %p\n", in); 
    printf("From function: %p\n", ptr); 

    return in; 
} 

int main(int argc, char** argv) { 

    int* out = (int*) malloc(sizeof(int)); 
    out[0] = 2; 
    printf("From main before call: %p\n", out); 
    out = just_testing(out); 
    printf("From main after call: %p\n", out); 

    return 0; 
} 

Cela me donne la sortie

From main before call: 0x19b2010 
Input address: 0x19b2010 
From function: 0x4011f1 
From main after call: 0x19b2010 

Malheureusement, les résultats de __builtin_return_address ne correspondent pas à l'adresse de la variable qui reçoit le revenir de la fonction, que je ne m'attendais pas.

Pourquoi les adresses ne sont-elles pas identiques? Je me réjouis également des suggestions constructives sur une approche différente en plus des deux que j'ai énumérés ici.

+0

Ce n'est pas ce que signifie "adresse de retour", et ce que vous voulez est impossible, désolé. Continuez simplement à passer le pointeur de destination en tant qu'argument; c'est assez standard. – Ryan

+0

Après avoir essayé quelques implémentations différentes, il semble que c'est vraiment la meilleure façon d'accomplir ce que je veux. Merci pour le conseil. – KindaTechy

Répondre

0

Autre solution possible pourrait être d'avoir la définition suivante: -

double* my_function(double* input, bool alloc) 
{ 
    double* output = input; 

    if(alloc) 
    { 
     //allocate new memory 
     double* output = (double*)malloc(...); 
    } 
    //else work with input memory 

    //do modifications here 

    return output; 
} 
+0

Bonne suggestion. Je l'ai juste implémenté et inclus varargs de sorte qu'il n'a besoin que de l'argument supplémentaire s'il est mis à jour. Toujours pas aussi propre que je le voudrais, et il y a toujours une possibilité de perdre le pointeur. – KindaTechy

+0

Oui, Besoin de prendre soin de la gestion de la mémoire. – MGpro

1

La solution est d'avoir plus propre deux fonctions distinctes:

#include <stdlib.h> 
#include <string.h> 

void compute_inplace(double *data) { 
    data[0] *= 2; 
} 

double *compute_copying(const double *input) { 
    double *output = malloc(sizeof *output * N); 
    if (output == NULL) 
     return NULL; 

    memcpy(output, input, sizeof *output * N); 
    compute_inplace(output); 
    return output; 
} 

Notez que la fonction de copie prend son argument comme pointeur vers const, ce qui aide si vous lui passez accidentellement une zone de mémoire en lecture seule.

+2

Je pense que la deuxième fonction devrait toujours retourner le pointeur. En dehors de cela, deux fonctions sont la meilleure solution car il est connu au moment de la compilation ce que le programmeur veut. –