Pourquoi le résultat de cette dissortingbution n’est-il pas une lvalue?

J’ai besoin de conseils avec ce comportement étrange – laisse ce code:

int ** p; 

Cela se comstack sans problème:

 p++; 

Mais ça:

 ((int**)p)++; 

Donne-moi ce message d’erreur: “error: lvalue required as increment operand” .

Je lance à p sur le type qu’il est déjà, rien ne change, alors quel est le problème? C’est la version simplifiée du problème que j’ai rencontré lorsque j’essayais de comstackr une ancienne version de gdb . Je suppose donc que cela a fonctionné et que quelque chose a changé. Une idée de ce qui ne va pas avec le deuxième exemple?

    Les anciennes versions de gcc supportent quelque chose appelé “lvalue jette” – si vous lancez quelque chose qui est une lvalue, le résultat est une lvalue et peut être traité comme tel. Son utilisation principale vous permet d’incrémenter un pointeur d’un montant correspondant à une taille différente:

     int *p; ++(char *)p; /* increment p by one byte, resulting in an unaligned pointer */ 

    Cette extension est obsolète depuis un certain temps autour de gcc v3.0 et supprimée dans gcc v4.0

    Pour faire la même chose dans les versions les plus récentes de gcc, vous devez effectuer une addition et une affectation (au lieu d’un incrément) en transmettant le pointeur sur le type pour l’ajout et le retour pour l’affectation:

     p = (int *)((char *)p + 1); 

    Notez que tenter de déréférencer le pointeur après cela est un comportement indéfini. Ne vous attendez donc pas à ce qu’il fasse quelque chose d’utile.

    Lorsque vous transtypez une expression, le résultat de cette expression est une valeur rvalue plutôt qu’une valeur lvalue. Intuitivement, un transtypage de caractères dit “donnez-moi la valeur que cette expression aurait si elle avait un autre type”, de sorte que le transtypage d’une variable dans son propre type produit toujours une valeur rvalue et non une valeur. Par conséquent, il n’est pas légal d’appliquer l’opérateur ++ au résultat d’une conversion de type, car ++ requirejs une valeur lvalue et vous fournissez une valeur rvalue.

    Cela dit, il est en principe possible de redéfinir le langage C afin que le fait de définir une valeur sur son propre type produise une valeur si l’expression d’origine est une valeur, mais pour des raisons de simplicité et de cohérence, je suppose que les concepteurs de langage ne l’ont pas fait.

    J’espère que cela t’aides!

    Pourquoi le résultat de cette dissortingbution n’est-il pas une lvalue?

    J’attire votre attention sur la section 6.5.4 de la spécification C99, ligne 4, note de bas de page 86, qui stipule:

    Un casting ne donne pas une valeur.

    Vous avez un casting.

    Le résultat n’est pas une valeur.

    L’opérateur ++ requirejs une valeur lvalue.

    Par conséquent, votre programme est une erreur.

    En langage C, toutes les conversions (y compris les conversions explicites) produisent toujours des valeurs. Aucune exception. Le fait que vous le diffusiez dans le même type ne le rend pas exempt de cette règle. (En fait, il serait étrange de s’attendre à ce qu’il fasse une exception aussi incohérente.)

    En fait, l’une des propriétés fondamentales de l’ensemble du langage C est qu’il convertit toujours les valeurs en rvalues ​​dans les expressions le plus rapidement possible. Les expressions Lvalues ​​in C sont comme le 115ème élément de la table de Mendeleev: elles mènent généralement une vie très courte, se décomposant rapidement en rvalues. C’est une différence majeure entre C et C ++, ce dernier essayant toujours de conserver les valeurs dans les expressions le plus longtemps possible (bien que, en C ++, cette conversion spécifique produise également une valeur rvalue).