La question portait sur c fonctions, pas c ++ static
telles que clarifiées dans les commentaires.
Je comprends ce qu'est une static
variable, mais qu'est-ce qu'une static
fonction?
Et pourquoi est-ce que si je déclare une fonction, disons void print_matrix
, disons a.c
(SANS a.h
) et que j'inclus "a.c"
- j'obtiens "print_matrix@@....) already defined in a.obj"
, MAIS si je la déclare comme static void print_matrix
alors elle se compile?
MISE À JOUR Juste pour clarifier les choses - je sais que l'inclusion .c
est mauvaise, comme beaucoup d'entre vous l'ont souligné. Je fais juste à l' espace temporairement clair main.c
jusqu'à ce que j'ai une meilleure idée de la façon de regrouper toutes ces fonctions en bonne .h
et .c
fichiers. Juste une solution temporaire et rapide.
la source
Il existe une grande différence entre les fonctions statiques en C et les fonctions membres statiques en C ++. En C, une fonction statique n'est pas visible en dehors de son unité de traduction, qui est le fichier objet dans lequel elle est compilée. En d'autres termes, rendre une fonction statique limite sa portée. Vous pouvez considérer une fonction statique comme étant "privée" à son fichier * .c (bien que ce ne soit pas strictement correct).
En C ++, "statique" peut également s'appliquer aux fonctions membres et aux membres de données des classes. Un membre de données statique est également appelé «variable de classe», tandis qu'un membre de données non statique est une «variable d'instance». Il s'agit de la terminologie Smalltalk. Cela signifie qu'il n'y a qu'une seule copie d'un membre de données statique partagée par tous les objets d'une classe, tandis que chaque objet a sa propre copie d'un membre de données non statique. Un membre de données statique est donc essentiellement une variable globale, c'est-à-dire un membre d'une classe.
Les fonctions membres non statiques peuvent accéder à tous les membres de données de la classe: statiques et non statiques. Les fonctions membres statiques ne peuvent fonctionner que sur les membres de données statiques.
Une façon de penser à cela est qu'en C ++, les membres de données statiques et les fonctions membres statiques n'appartiennent à aucun objet, mais à la classe entière.
la source
Il existe deux utilisations du mot-clé static lorsqu'il s'agit de fonctions en C ++.
La première consiste à marquer la fonction comme ayant un lien interne afin qu'elle ne puisse pas être référencée dans d'autres unités de traduction. Cette utilisation est déconseillée en C ++. Les espaces de noms sans nom sont préférés pour cette utilisation.
La deuxième utilisation se situe dans le contexte d'une classe. Si une classe a une fonction membre statique, cela signifie que la fonction est membre de la classe (et a l'accès habituel aux autres membres), mais elle n'a pas besoin d'être invoquée via un objet particulier. En d'autres termes, à l'intérieur de cette fonction, il n'y a pas de pointeur "this".
la source
Exemple de portée multi-fichiers exécutable minimal
Ici, j'illustre comment
static
affecte la portée des définitions de fonction sur plusieurs fichiers.ac
principal c
GitHub en amont .
Compiler et exécuter:
Production:
Interprétation
sf
, une pour chaque fichierf
Comme d'habitude, plus la portée est petite, mieux c'est, alors déclarez toujours les fonctions
static
si vous le pouvez.En programmation C, les fichiers sont souvent utilisés pour représenter des "classes" et les
static
fonctions représentent des méthodes "privées" de la classe.Un modèle C commun consiste à passer une
this
structure comme premier argument de "méthode", ce qui est essentiellement ce que fait C ++ sous le capot.Ce que les normes en disent
C99 N1256 draft 6.7.1 "Storage-class specifiers" dit qu'il
static
s'agit d'un "stockage-class specifier".6.2.2 / 3 "Liens d'identifiants" dit
static
impliqueinternal linkage
:et 6.2.2 / 2 dit que
internal linkage
se comporte comme dans notre exemple:où "unité de traduction" est un fichier source après le prétraitement.
Comment GCC l'implémente-t-il pour ELF (Linux)?
Avec la
STB_LOCAL
reliure.Si nous compilons:
et démontez la table des symboles avec:
la sortie contient:
donc la liaison est la seule différence significative entre eux.
Value
est juste leur décalage dans la.bss
section, nous nous attendons donc à ce qu'il diffère.STB_LOCAL
est documenté sur la spécification ELF à http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :ce qui en fait un choix parfait pour représenter
static
.Les fonctions sans statique sont
STB_GLOBAL
, et la spécification dit:ce qui est cohérent avec les erreurs de liaison sur plusieurs définitions non statiques.
Si nous augmentons l'optimisation avec
-O3
, lesf
symbole est entièrement supprimé de la table des symboles: il ne peut en aucun cas être utilisé de l'extérieur. TODO pourquoi garder les fonctions statiques sur la table des symboles quand il n'y a pas d'optimisation? Peuvent-ils être utilisés pour quelque chose?Voir également
extern
est l'opposé destatic
, et les fonctions sont déjàextern
par défaut: Comment utiliser extern pour partager des variables entre des fichiers source?Espaces de noms anonymes C ++
En C ++, vous souhaiterez peut-être utiliser des espaces de noms anonymes au lieu de statiques, ce qui produit un effet similaire, mais masque davantage les définitions de type: espaces de noms sans nom / anonymes vs fonctions statiques
la source
void f() { puts("sf"); }
(c'est-à-dire deux définitions def()
) provoque un comportement indéfini sans diagnostic requis. C'est un problème de qualité de l'éditeur de liens pour voir réellement un message d'erreur.Ce qui suit concerne les fonctions C simples - dans une classe C ++, le modificateur «statique» a une autre signification.
Si vous n'avez qu'un seul fichier, ce modificateur ne fait absolument aucune différence. La différence vient des projets plus importants avec plusieurs fichiers:
En C, chaque "module" (une combinaison de sample.c et sample.h) est compilé indépendamment et ensuite chacun de ces fichiers objets compilés (sample.o) est lié ensemble à un fichier exécutable par l'éditeur de liens.
Disons que vous avez plusieurs fichiers que vous incluez dans votre fichier principal et que deux d'entre eux ont une fonction qui n'est utilisée qu'en interne pour plus de commodité appelée
add(int a, b)
- le compilateur créerait facilement des fichiers objets pour ces deux modules, mais l'éditeur de liens générera une erreur, car il trouve deux fonctions avec le même nom et il ne sait pas laquelle il doit utiliser (même s'il n'y a rien à lier, car elles ne sont pas utilisées ailleurs mais dans son propre fichier).C'est pourquoi vous faites de cette fonction, qui n'est utilisée qu'en interne, une fonction statique. Dans ce cas, le compilateur ne crée pas le drapeau typique "vous pouvez lier cette chose" pour l'éditeur de liens, de sorte que l'éditeur de liens ne voit pas cette fonction et ne génère pas d'erreur.
la source
Premièrement: c'est généralement une mauvaise idée d'inclure un
.cpp
fichier dans un autre fichier - cela conduit à des problèmes comme celui-ci :-) La manière normale est de créer des unités de compilation séparées et d'ajouter un fichier d'en-tête pour le fichier inclus.Deuxièmement:
C ++ a une terminologie déroutante ici - je ne le savais pas jusqu'à ce que cela soit indiqué dans les commentaires.
a)
static functions
- hérité de C, et de quoi vous parlez ici. En dehors de toute classe. Une fonction statique signifie qu'elle n'est pas visible en dehors de l'unité de compilation actuelle - donc dans votre cas a.obj a une copie et votre autre code a une copie indépendante. (Ballonnement de l'exécutable final avec plusieurs copies du code).b)
static member function
- ce que l'Orientation Objet appelle une méthode statique . Vit dans une classe. Vous appelez cela avec la classe plutôt que via une instance d'objet.Ces deux définitions de fonctions statiques différentes sont complètement différentes. Soyez prudent - voici des dragons.
la source
les définitions de fonctions statiques marqueront ce symbole comme interne. Il ne sera donc pas visible pour les liens de l'extérieur, mais uniquement pour les fonctions dans la même unité de compilation, généralement le même fichier.
la source
Une fonction statique est une fonction qui peut être appelée sur la classe elle-même, par opposition à une instance de la classe.
Par exemple, un non statique serait:
Cette méthode fonctionne sur une instance de la classe, pas sur la classe elle-même. Cependant, vous pouvez avoir une méthode statique qui peut fonctionner sans avoir d'instance. Ceci est parfois utilisé dans le modèle Factory:
la source
Nit mineur: les fonctions statiques sont visibles pour une unité de traduction, qui dans la plupart des cas pratiques est le fichier dans lequel la fonction est définie. L'erreur que vous obtenez est communément appelée violation de la règle de définition unique.
La norme dit probablement quelque chose comme:
C'est la façon C de voir les fonctions statiques. Ceci est cependant obsolète en C ++.
En C ++, en outre, vous pouvez déclarer des fonctions membres statiques. Ce sont principalement des métafonctions, c'est-à-dire qu'elles ne décrivent / modifient pas le comportement / l'état d'un objet particulier mais agissent sur l'ensemble de la classe elle-même. Cela signifie également que vous n'avez pas besoin de créer un objet pour appeler une fonction membre statique. En outre, cela signifie également que vous n'accédez aux variables membres statiques qu'à partir d'une telle fonction.
J'ajouterais à l'exemple de Parrot le modèle Singleton qui est basé sur ce type de fonction membre statique pour obtenir / utiliser un seul objet pendant toute la durée de vie d'un programme.
la source
La réponse à la fonction statique dépend de la langue:
1) Dans les langages sans OOPS comme C, cela signifie que la fonction n'est accessible que dans le fichier où elle est définie.
2) Dans les langages avec OOPS comme C ++, cela signifie que la fonction peut être appelée directement sur la classe sans en créer d'instance.
la source
static
a également une portée de fichier, comme elle l'est en C.Puisque la fonction statique n'est visible que dans ce fichier. En fait, le compilateur peut faire une optimisation pour vous si vous déclarez "statique" à une fonction.
Voici un exemple simple.
principal c
Et compilez avec
Vous verrez que cela a échoué. Parce que vous n'implémentez même pas la fonction ghost ().
Mais que faire si nous utilisons la commande suivante.
Il réussit et ce programme peut être exécuté normalement.
Pourquoi? Il y a 3 points clés.
Ce n'est que si ces 3 conditions sont toutes remplies que vous pouvez passer la compilation. En raison de cette déclaration "statique", le compilateur peut confirmer que test () ne sera JAMAIS appelé dans un autre fichier. Votre compilateur peut supprimer test () lors de la compilation. Comme nous n'avons pas besoin de test (), peu importe si ghost () est défini ou implémenté.
la source
Commençons par le début.
Tout est basé sur une chose appelée "liaison":
Si une fonction est définie sans spécificateur de classe de stockage, la fonction a une
extern
liaison par défaut par défaut:Cela signifie que - si votre programme contient plusieurs unités de traduction / fichiers source (
.c
ou.cpp
) - la fonction est visible dans toutes les unités de traduction / fichiers source de votre programme.Cela peut être un problème dans certains cas. Que faire si vous souhaitez utiliser deux fonctions différentes (définitions), mais avec le même nom de fonction dans deux contextes différents (en fait le fichier-contexte).
En C et C ++, le
static
qualificatif de classe de stockage appliqué à une fonction à portée de fichier (pas une fonction membre statique d'une classe en C ++ ou une fonction dans un autre bloc) vient maintenant pour aider et signifie que la fonction respective n'est visible qu'à l'intérieur de l'unité de traduction / le fichier source dans lequel il a été défini et non dans les autres TLU / fichiers.Ainsi, une
static
fonction n'a de sens que si:Votre programme est composé de plusieurs unités de traduction / fichiers source (
.c
ou.cpp
).et
Vous souhaitez limiter l'étendue d'une fonction au fichier dans lequel la fonction spécifique est définie.
Dans le cas contraire les deux de ces exigences correspondent, vous n'avez pas besoin d'envelopper autour de votre tête sur l' admissibilité d' une fonction
static
.Notes annexes:
Comme déjà mentionné, une
static
fonction n'a absolument aucune différence entre C et C ++, car il s'agit d'une fonction C ++ héritée de C.Il n'a pas d'importance que dans la communauté C ++, il y ait un débat déchirant sur la dépréciation des fonctions qualificatives par
static
rapport à l'utilisation d' espaces de noms sans nom à la place, initialement initialisé par un paragraphe mal placé dans la norme C ++ 03, déclarant l'utilisation de fonctions statiques obsolètes qui ont été bientôt révisées par le comité lui-même et supprimées en C ++ 11.Cela a fait l'objet de diverses questions SO:
Espaces de noms sans nom / anonymes vs fonctions statiques
Supériorité de l'espace de noms sans nom sur statique?
Pourquoi un espace de noms sans nom est une alternative "supérieure" à statique?
Obsolescence du mot-clé statique ... pas plus?
En fait, il n'est pas encore obsolète selon la norme C ++. Ainsi, l'utilisation des
static
fonctions est toujours légitime. Même si les espaces de noms sans nom présentent des avantages, la discussion sur l’utilisation ou la non-utilisation de fonctions statiques en C ++ est sujette à une seule opinion (fondée sur l’opinion) et ne convient pas à ce site Web.la source