Lorsque j'utilise va_arg pour importer par exemple -1 , et je spécifie int comme type de données, il l'obtient sans problème. Mais si je spécifie long int , long long int ou intmax_t , il affiche 4294967295 .
Si j'avais spécifié unsigned int , cela aurait été compréhensible. Mais je spécifie un type de données signé qui est encore plus grand qu'un int. Comment puis-je obtenir ce résultat?
va_arg(valist, int) -> -1 (OK) va_arg(valist, long int) -> 4294967295 (???)
4 Réponses :
-1 est considéré comme une constante int , selon la définition de la langue.
Si vous voulez une constante long int , vous devez ajouter un L: -1L .
En fait, -1 est une expression unaire (C 2018 6.5.3 1), pas une constante. Le caractère - est un jeton séparé et ne peut pas faire partie d'une constante entière (6.4.4.1 1). (Par exemple, -2147483648 est un long int lorsque int vaut 32 bits et long int est plus large, car 217483648 n'est pas représentable dans int même si −2147483648 l'est.)
L'expression -1 est de type int (puisque la constante 1 est de type int et appliquant le code> - qui conserve le type), vous devez donc le récupérer à partir de la liste des arguments de variable avec ce type. Si vous essayez d'utiliser quelque chose comme long int , vous invoquez un comportement non défini car les types peuvent ne pas être de la même taille, c'est-à-dire que vous poussez 4 octets sur la pile mais que vous essayez de lire 8 octets. < / p>
Ce qui s'est probablement passé dans ce cas, c'est que 4 octets ont été lus avec tous les bits définis (le -1 que vous avez passé) puis 4 octets supplémentaires ont été lus qui étaient tous à 0. Ces 8 octets ont été interprétés avec un ordre d'octets petit boutien comme un 8 bit long vous donne la valeur que vous avez vue. Mais encore une fois, c'est un comportement indéfini. Si ces 4 octets suivants avaient été autre chose que 0, vous auriez eu une valeur différente.
Si vous aviez réussi -1L , vous auriez besoin d'utiliser long int .
En fait, -1 est une expression unaire (C 2018 6.5.3 1), pas une constante. Le caractère - est un jeton séparé et ne peut pas faire partie d'une constante entière (6.4.4.1 1). (Par exemple, -2147483648 est un long int lorsque int vaut 32 bits et long int est plus large, car 217483648 n'est pas représentable dans int même si −2147483648 l'est.)
Vous devez utiliser int , puis (implicitement ou explicitement) le convertir en long . va_arg utilise la taille du type de données que vous lui transmettez, et essayer de récupérer le mauvais type de données est un comportement indéfini.
Exemple:
func(arg1, arg2, arg3, -1L);
Une autre option est de passer -1L à la fonction, puis d'appeler va_arg avec long:
long a = va_arg(ap, int);
mais n'est-ce pas -1 un int ainsi qu'un long int ainsi qu'un long long int?
@ nightowl92 no.
@ nightowl92 -1 n'est qu'un int . -1L est un long int , et -1LL est un long long int .
1 est un littéral intégral de type int . Comment savons-nous cela? Nous vérifions la référence :
Le type du littéral entier est le premier type dans lequel la valeur peut s'adapter, à partir de la liste des types qui dépend de la base numérique et quel suffixe entier a été utilisé.
Strictement parlant, -1 est une expression qui évalue un objet de type int avec la valeur -1 .
Si vous voulez explicitement un type, vous pouvez utiliser l'un des suffixes donnés. Si vous voulez un long utilisez -1L
En fait, -1 est une expression unaire (C 2018 6.5.3 1), pas une constante ou un littéral. Le caractère - est un jeton séparé et ne peut pas faire partie d'une constante entière (6.4.4.1 1). (Par exemple, -2147483648 est un long int lorsque int vaut 32 bits et long int est plus large, car 217483648 n'est pas représentable dans int même si −2147483648 l'est.)
@EricPostpischil Merci pour vos commentaires, c'est très intéressant. J'ai essayé d'ajouter cela.
Vous devez utiliser
intpuis le cast enlong.va_listutilise en fait la taille du type de données.Si vous cochez par exemple
sizeof (int)etsizeof (long), sont-ils identiques? Je suppose qu'ils ne le sont pas. Et vraiment, essayez de créer un exemple minimal reproductible pour nous le montrer. Et peut-être actualiser comment poser de bonnes questions , ainsi que cette liste de contrôle de question .exactement, long est plus gros, n'est-ce pas? et c'est signé n'est-ce pas? alors pourquoi ne pourrait-il pas obtenir un -1? les types de données non signés ne peuvent pas avoir de nombres négatifs, ils seront traduits en valeur INT_MAX. Mais ici, c'est une valeur signée qui a suffisamment d'espace pour stocker -1. Alors pourquoi le change-t-il comme s'il s'agissait d'un type de données non signé?
(a) Montrez le code réel pour que les gens puissent en discuter concrètement, et non à partir de descriptions vagues (b) Lorsque vous appelez une fonction, les arguments ont des types spécifiques. Si vous n'avez pas déclaré ces types dans une déclaration de fonction avec un prototype, ils utilisent par défaut certains types selon les promotions d'argument par défaut. Lorsque vous utilisez
va_argpour obtenir les valeurs des arguments, la norme C spécifie le comportement uniquement si vous fournissez un pointeur vers un type compatible. L'implémentation C utilise le type pour localiser les données. Il ne suffit pas que la valeur soit représentable dans le type; vous devez en fait faire correspondre les types.