229 votes

De retour d'une `struct` partir d'une fonction en C

Aujourd'hui, j'enseigne à un couple d'amis comment utiliser C structs. L'un d'eux a demandé si vous pouviez retourner un struct à partir d'une fonction, à laquelle j'ai répondu: "Non! Vous souhaitez renvoyer les pointeurs dynamiquement malloced structs à la place."

Venant de quelqu'un qui d'abord est-ce que C++, je m'attendais à ne pas être en mesure de revenir structs par des valeurs. En C++, vous pouvez surcharger la operator = pour vos objets et prend tout son sens à une fonction pour retourner votre objet par valeur. En C, cependant, vous n'avez pas cette option et donc il m'a fait penser que le compilateur est en train de faire. Considérez les points suivants:

struct MyObj{
    double x, y;
};

struct MyObj foo(){
    struct MyObj a;

    a.x = 10;
    a.y = 10;

    return a;
}        

int main () {

    struct MyObj a;

    a = foo();    // This DOES work
    struct b = a; // This does not work

    return 0;
}    

Je comprends pourquoi struct b = a; ne devraient pas travailler -- vous ne pouvez pas surcharger operator = pour le type de données. Comment est-ce que a = foo(); compile bien? Signifie-t-il autre chose que l' struct b = a;? Peut-être que la question à se poser est: qu'est-Ce exactement ne l' return déclaration dans le cadre de = signe?

[edit]: Ok, je viens de relever struct b = a est une erreur de syntaxe -- c'est exact, et je suis un idiot! Mais qui le rend encore plus compliqué!!! À l'aide de struct MyObj b = a fonctionne en effet! Ce qui me manque ici?

270voto

Carl Norum Points 114072

Vous pouvez revenir à une structure à partir d'une fonction (ou d'utiliser l' = opérateur) sans aucun problème. C'est une partie bien définie de la langue. Le seul problème avec struct b = a , c'est que vous n'avez pas de fournir un ensemble de type. struct MyObj b = a fonctionnent très bien. Vous pouvez passer des structures de fonctions - une structure est exactement la même que n'importe quel type intégré, pour les fins de la transmission de paramètres, les valeurs de retour, et de l'affectation.

Voici une démonstration simple programme qui fait tous les trois - transmet une structure en paramètre et retourne une structure à partir d'une fonction, et utilise des structures dans les instructions d'affectation:

#include <stdio.h>

struct a {
   int i;
};

struct a f(struct a x)
{
   struct a r = x;
   return r;
}

int main(void)
{
   struct a x = { 12 };
   struct a y = f(x);
   printf("%d\n", y.i);
   return 0;
}

L'exemple suivant est à peu près exactement la même chose, mais utilise le haut- int type pour les besoins de la démonstration. Les deux programmes ont le même comportement à l'égard de passe-par-valeur pour le paramètre de passage, de cession, etc.:

#include <stdio.h>

int f(int x) 
{
  int r = x;
  return r;
}

int main(void)
{
  int x = 12;
  int y = f(x);
  printf("%d\n", y);
  return 0;
}

43voto

Greg Hewgill Points 356191

Lors d'un appel tel que a = foo();, le compilateur peut pousser l' adresse du résultat de la structure sur la pile et les transmet comme un "caché" pointeur à l' foo() fonction. Effectivement, il pourrait devenir quelque chose comme:

void foo(MyObj *r) {
    struct MyObj a;
    // ...
    *r = a;
}

foo(&a);

Toutefois, l'exacte mise en œuvre de cette fonction dépend du compilateur et/ou de la plateforme. Comme Carl Norum notes, si la structure est assez petit, il pourrait même être passé complètement dans un registre.

18voto

JaredPar Points 333733

L' struct b ligne ne fonctionne pas parce que c'est une erreur de syntaxe. Si vous développez pour inclure le type il fonctionne très bien

struct MyObj b = a;  // Runs fine

De ce que C est en train de faire ici est essentiellement un memcpy à partir de la source struct à la destination. Cela est vrai tant pour l'affectation et le retour de l' struct valeurs (et vraiment, toutes les autres valeurs de C)

17voto

Giorgio Points 1724

Aussi loin que je me souvienne, les premières versions de C uniquement autorisé à retourner une valeur qui pourrait s'adapter à un processeur de registre, ce qui signifie que vous ne pouviez retourner un pointeur vers une struct. La même restriction appliquée à des arguments de la fonction.

Les versions les plus récentes permettent de transmettre autour de grands objets de données comme des structures. Je pense que cette fonctionnalité était déjà fréquent au cours des années quatre-vingt ou début des années nonante.

Tableaux, cependant, peut encore être adopté et renvoyé uniquement à titre indicatif.

4voto

DigitalRoss Points 80400

Vous pouvez attribuer des structures en C. a = b; est une syntaxe valide.

Il vous suffit de gauche, une partie de ce type -- la structure de la balise -- dans votre ligne qui ne fonctionne pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X