33 votes

Quel type est un nom de fonction en C?

J'ai toujours compris que, dans C, func et &func étaient équivalentes. Je suppose qu'ils doivent à la fois être de type pointeur, qui est de 8 octets sur mon Win64 système. Cependant, j'ai juste essayé ceci:

#include <stdio.h>

int func(int x, int y)
{
    printf("hello\n");
}

int main()
{
    printf("%d, %d\n", sizeof(&func), sizeof(func));
    return 0;
}

Et s'attendent à obtenir la sortie 8, 8 a été surpris de se 8, 1 à la place.

Pourquoi est-ce? Quel type exactement est - func? Il semble être de type char ou l'équivalent.
Ce qui se passe ici?

J'ai compilé ce avec gcc -std=c99 si cela fait une différence.

37voto

ouah Points 75311

Ce type est un nom de fonction en C?

Un nom de fonction ou la fonction de désignation a un type de fonction. Lorsqu'il est utilisé dans une expression, sauf quand c'est l'opérande de sizeof ou & de l'opérateur, il est converti en type "fonction de retour de type" type "pointeur vers une fonction de retour de type". (C'est spécifié dans C99, 6.3.2.1p4).

Maintenant

sizeof(func)

n'est pas valide C sizeof n'est pas permis avec un opérande de type de fonction. Ceci est spécifié dans les contraintes de l' sizeof opérateur:

(C99, 6.5.3.4p1 Contraintes) "L'opérateur sizeof ne doit pas être appliquée à une expression qui a la fonction de type ou d'un type incomplète, à la mise entre parenthèses du nom de ce type, ou une expression qui désigne un membre de champ."

Mais

sizeof(func)

est autorisé dans GNU C.

Il est une extension GNU GNU C qui permet et dans GNU C sizeof avec un opérande de type fonction des rendements en 1:

6.23 Arithmétique à vide et des fonctions Pointeurs

[...] sizeof est également autorisé à vide et sur des types de fonction, et retourne 1.

http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html

12voto

Keith Thompson Points 85120

Donnée:

int func(int x, int y) { /* ... */ }

l'expression func est de type fonction. Plus précisément, il est de type int(int, int),, C est la syntaxe pour le type "fonction à deux int paramètres de revenir int. (Vous ne verrez pas souvent que la syntaxe particulière, car il n'est pas commun de se référer à des types de fonction directement.)

Dans la plupart des contextes, une expression de type de fonction est implicitement converti en un pointeur vers la fonction; dans ce cas, le pointeur est de type int(*)(int, int).

Les contextes dans lesquels cette conversion implicite ne pas se produire sont les suivants:

  1. Lorsque l'expression est l'opérateur unaire &; dans ce cas, &func rendements de l'adresse de la fonction (comme func par elle-même généralement le cas); et

  2. Lorsque l'expression est l'opérande de sizeof. Sans cette exception, sizeof func donnerait la taille d'un pointeur de fonction. Au lieu de cela, c'est une violation de contrainte, nécessitant un diagnostic du compilateur.

(Une note de côté: Cette conversion ne se produire lorsque le nom de la fonction est utilisée dans un appel de fonction. L' () "opérateur" (le standard ne veut pas l'appeler comme ça) nécessite un préfixe de pointeur de fonction type.)

gcc arrive à avoir une extension standard, elle permet l'arithmétique des pointeurs sur des pointeurs de fonction et sur le type void*, agissant comme l'arithmétique des pointeurs sur char* des pointeurs (c'est à dire, il fonctionne dans les unités d'octets). Malheureusement, à mon humble avis, gcc n'via une bidouille, la définition de la taille de types de fonctions et de type void à 1. C'est pourquoi vous obtenez sizeof func == 1; si vous activez l'un de la norme conforme modes (par exemple, gcc -std=c99 -pedantic), vous recevrez un avertissement.

D'ailleurs, ne pas utiliser %d pour imprimer le résultat de l' sizeof. sizeof donne un résultat de type size_t. Si votre application prend en charge (C99 ou plus tard), utilisez %zu; dans le cas contraire, vous devez utiliser un cast pour convertir explicitement l' size_t de la valeur à quelque chose que vous pouvez imprimer. Par exemple:

printf("%lu\n", (unsigned long)sizeof &func);

1voto

Kaz Points 18072

Les noms n'ont pas un type dans C. Certains types de noms de désigner des entités qui ont un type, telles que la définition de type des noms, des objets ou des fonctions. D'autres types de noms de désigner des entités qui n'ont pas de type, comme les symboles de préprocesseur ou goto labels. Encore d'autres types de noms de simplement désigner les types eux-mêmes, à savoir l' typedef noms.

Le nom d'une fonction désigne une entité qui a la fonction de type. Cette fonction comprend le type de retour, et (peut-être incomplète) informations sur les paramètres.

Lorsque des fonctions sont utilisées comme valeurs, ils sont toujours manipulés comme de pointeur vers des types de fonction. Une fonction en tant que telle ne peut pas être passé autour dans un portable C programme, mais un pointeur vers une fonction peut être.

Sur le plan conceptuel, même dans un appel direct comme foo(), ce qui se passe c'est qu' foo, une expression désignant une fonction, lors de l'évaluation est implicitement converti en un pointeur vers la fonction de valeur. L' () appel de fonction postfix exploitant, puis appelle la fonction par le biais de ce pointeur.

Il y a une règle qu'une expression qui a la fonction de type de produit d'une valeur de pointeur, sauf si l'expression est l'opérande de l' & (adresse) ou de l' sizeof de l'opérateur. func et &func ne sont équivalents dans le sens où ils produisent la même valeur. func produit une valeur de pointeur implicitement. &func supprime l'implicite de la génération d'un pointeur (func , l'opérande de & et donc la conversion est supprimée), mais ensuite, & prend l'adresse.

Donc vous pouvez voir qu' sizeof &func et sizeof func sont différentes. Le premier prend la taille d'un pointeur, et ce dernier tente de prendre la taille d'une fonction.

En prenant la taille d'une fonction est une violation de contrainte dans C: il nécessite un diagnostic à partir d'une mise en œuvre conforme à la norme. Si le programme reste se traduit par une valeur d' 1 est produit lorsqu'il est exécuté, c'est un "bonus" d'un comportement spécifique à la langue de votre mise en œuvre. Il n'est pas dans la langue standard.

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