Le type struct est-il vraiment comme les autres ?

Certaines manipulations semblent acceptées avec les structures mais pas avec les types de base du C

Le problème exposé dans ce sujet a été résolu.

Bonjour,

En faisant des tests sur le cours du site, je tombe sur un code qui ne compile pas, sans pouvoir l’expliquer :

struct Temps {
	unsigned heures;
	unsigned minutes;
	unsigned secondes;
};

int main()
{
	struct Temps *pTemps = &(struct Temps) {.heures = 6, .minutes = 7, .secondes = 8};
	int *pInt = &(int) 5;

	return 0;
}

L’erreur se trouve sur la ligne 10 : message du compilateur gcc :

main.c: In function 'main':
main.c:10:14: error: lvalue required as unary '&' operand
  int *pInt = &(int) 5;
              ^

Sans cette ligne, le code compile sans sourciller. Mais pourquoi cette différence. Ma question est purement théorique, oui. D’aucuns pourraient même dire "sans intérêt". N’hésitez pas à vous y intéresser cela dit :euh: Merci d’avance !

Il faut vérifier, mais je pense que c’est 5 qui n’est pas comme les autres, ça doit être un literal, qui n’est donc pas une lvalue, alors qu’un objet initialisé avec un identifiant désigné est forcément une struct ou une union, qui sont des lvalues.

Grosso modo, tu as un littéral composée (compound literal) vs un litéral.

Hors le premier occupe un espace en mémoire l’autre normalement non et donc on ne peut pas prendre l’adresse de quelques chose qui n’a pas d’adresse.

Tu peux bien-sûr tricher :

   int *pInt = &(int){5};

Pour ce type de question, je pense qu’il vaut mieux directement lire dans la norme. Je l’ai lu plein de fois mais là je doute sur les termes exates.

+0 -0

Ta démarche est surprenante.

Ton code ne compile pas sur la ligne int *pInt. Et dans ta question, tu te focalises sur la structure qui est juste avant. Bizarre.

Je testerais simplement ce code :

int main()
{
	int *pInt = &(int) 5;

	return 0;
}

Pour vérifier si ça plante toujours, ce qui mettrait définitivement hors de cause les structures.

Et évidemment, ça va planter. Ici, tu demandes l’adresse mémoire du nombre 5. Tous les objets déclarés dans ton programme ont une adresse mémoire, eux et uniquement eux (euhhhh, presque).

Non mais juste comme ça.

int main(void)
{
   (int){5} = 3;
   return 0;
}

Est tout à fait valide.

+0 -0

mais

int *p = &(int) 5;

ne l’est pas. La raison c’est que 5, ou (int) 5, ne sont pas des "lvalues".

Norme C11

  • 6.3.2.1 An lvalue is an expression (with an object type other than void) that potentially designates an object;
  • 3.15 Object. region of data storage in the execution environment, the contents of which can represent values
  • 6.5.3.2 The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

Historiquement une "lvalue" est un truc qui peut apparaître en partie gauche d’une affectation (left value). Donc pour lequel "espace de stockage de données" a été réservé, pour qu’on puisse lui affecter une valeur. Ce qui n’est pas le cas des constantes numériques.

Dans l’exemple donne au départ, l’opérateur & agit sur un champ d’une structure, qui est un objet (le champ, et la structure) donc une lvalue.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte