1
votes

Syntaxe incompréhensible en c / c ++ !! pourquoi pouvons-nous malloc un tampon comme celui-ci?

Aujourd'hui, j'ai remarqué un tas de code qui instancie une structure comme ci-dessous alors que ServiceMsg est une structure.

ServiceMsg *msg = (ServiceMsg *)malloc(sizeof * msg);

Je n'ai jamais vu malloc peut être utilisé comme ça. Quelqu'un peut-il m'expliquer cela ??? la taille du tampon est souvent assignée comme ce malloc (sizeof (int) * n) comme je le sais ..


4 commentaires

C'est sizeof(*msg) , pas une multiplication. (Et un new msg serait un million de fois meilleur (Et un pointeur intelligent encore un million de fois meilleur (Et il n'y a pas de langage appelé C/C++ )))


@john Pourquoi ça?


@ KenY-N Vous savez que je pense que j'aurais repéré cela sans l'espace entre le * et msg .


Pour que cela soit clair pour l'OP. Les parenthèses ne sont requises dans sizeof(X) si X est un type. Si X est une expression (comme ci-dessus), ils ne le sont pas.


4 Réponses :


3
votes

Dans l'extrait,

 ServiceMsg *msg = malloc(sizeof(*msg));

est le même que

 ServiceMsg *msg = (ServiceMsg *)malloc( 1* sizeof(*msg));

ce qui est mieux écrit comme

  ServiceMsg *msg = (ServiceMsg *)malloc(sizeof * msg);

Pour élaborer, malloc() attend une taille comme argument, et dans cet appel, la taille que nous passons est sizeof(*msg) , c'est-à-dire sizeof (ServiceMsg ) .

Cela dit, veuillez consulter cette discussion sur pourquoi ne pas convertir la valeur de retour de malloc () et de la famille en C ..


3 commentaires

... ou ServiceMsg* msg = new ServiceMsg; ou même auto msg = std::make_unique<ServiceMsg>();


@TedLyngmo uniquement si c'est le RPC, et j'ai gagné; n'utilisez pas malloc dans le RPC.


Soupir, je n'ai pas vu le double étiquetage de la question ...



0
votes

Il serait plus clair de réécrire cet appel où l'expression ressemble à une expression de multiplication

malloc(sizeof ( ServiceMsg ) );

comme

malloc(sizeof ( *msg ) );

L'opérateur sizeof est défini de la manière suivante

sizeof unary-expression
sizeof ( type-name )

L'expression *msg qui déréférence le msg du pointeur est une expression unaire. Le type de l'expression est déterminé (dans ce cas, il s'agit de ServiceMsg ) et la taille d'un objet de ce type est calculée. L'expression elle-même n'est pas évaluée. Le compilateur détermine uniquement son type.

Vous pouvez mettre cette expression unaire entre parenthèses pour obtenir une expression principale comme

malloc(sizeof *msg);

Dans cet enregistrement, cet enregistrement ressemble à cet enregistrement

malloc(sizeof * msg);


0 commentaires

3
votes

Il y a quelques détails qui pourraient rendre les choses déroutantes:

  • L'opérateur sizeof peut être utilisé de deux manières: soit avec des parenthèses sizeof(type) , mais alors l'argument doit être de type int . Ou sans parenthèse sizeof expr , alors l'argument peut être une expression. Mais bien sûr, une expression peut contenir une parenthèse en elle-même ...

  • Dans votre cas, sizeof *msg prend la taille de l'expression *msg , ce qui signifie dé-référencer le pointeur msg (ce n'est pas l'opérateur de multiplication!) Donc nous nous retrouvons avec une variable temporaire "lvalue" de type ServiceMsg . Qui a la taille d'un ServiceMsg .

  • Normalement, dé-référencer une variable de pointeur sur la même ligne qu'elle est déclarée serait un gros non-non, elle n'est pas initialisée et ne pointe pas encore vers un emplacement raisonnable. Le hic, c'est que l'opérateur sizeof n'évalue pas réellement (n'exécute) pas son opérande, donc l'expression *msg n'est jamais exécutée et le dé-référencement ne se produit jamais.

C'est pourquoi le code fonctionne. Ce style est souvent même recommandé, car vous n'avez pas à vous soucier du type sur lequel le pointeur pointe - il est toujours de type* ptr = malloc(sizeof *ptr); indépendamment de ce que vous allouez.

Le cast en (ServiceMsg*) dans votre code est superflu.


2 commentaires

Merci pour l'explication!! mais qu'est-ce que cela signifie: tapez ptr * = malloc (sizeof * ptr) ?? Je change de type en int et je l'ai essayé dans ma machine, ça bloque lors de la compilation.


@CaiyiZhou C'était une faute de frappe, corrigée. Mais à part cela, je voulais dire qu'au lieu de type vous pouvez y écrire n'importe quel type valide et cela fonctionne de la même manière.



0
votes

Nettoyer ça un peu, on obtient

T *p;
...
p = calloc( N, sizeof *p );

qui est exactement le même que

T *p = calloc( N, sizeof *p );

N == 1 . C'est un idiome assez courant en C pour allouer dynamiquement de la mémoire:

T *p;
...
p = malloc( N * sizeof *p );

ou

T *p = malloc( N * sizeof *p ); // for any non-function type T

ou

ServiceMsg *msg = malloc(N * sizeof *msg);

ou

ServiceMsg *msg = malloc(sizeof *msg);

Il a l'avantage de ne pas répéter les informations de type, ce qui facilite la maintenance.

Le cast est inutile 1 , et comme le type de l'expression *msg est ServiceMessage , sizeof *msg == sizeof( ServiceMessage ) .

Rappelez-vous que sizeof est un opérateur, pas une fonction - les parenthèses ne sont nécessaires que si l'opérande est un nom de type comme ServiceMessage ou int ou char , ou s'il s'agit d'une expression arithmétique comme 1 + 2 . Puisque sizeof est un opérateur unaire, il a une priorité plus élevée qu'un opérateur arithmétique, donc sizeof 1 + 2 est analysé comme (sizeof 1) + 2 , ce qui n'est probablement pas ce que vous voulez.


  1. Sauf si vous compilez ce code en C ++ ou que vous utilisez une ancienne implémentation K&R. Avant C89, les fonctions *alloc char * au lieu de void * , donc un cast était nécessaire si la cible n'était pas un char * . C ++ n'autorise pas la conversion implicite de void * vers d'autres types de pointeurs, il nécessite donc également un cast, mais si vous écrivez du C ++, vous ne devriez de toute façon pas utiliser la gestion de la mémoire de style C.


0 commentaires