De la programmation système

[quote=“panthere”][quote]
D’une part les appels systèmes (je présume que c’est de cela dont tu parle) sont directement accessible en C++ (il a était conçu pour), d’autre part rien oblige à utiliser de manière direct les appels systèmes pour faire de « la programmation système ».
[/quote]

Vu comme ça, je dirais que wrapper du C pour en faire du C++ … et pourquoi réinventer la roue , c est sure que tu peux faire sans mai bon …[/quote]
Parce qu’il est ainsi possible d’utiliser des concepts objets inexistants en C, par exemple ?
Écrire une pile tcp/ip en langage objet est un pur bonheur pour qui sait apprécier la programmation objet.

J’avais travaillé sur ce projet : mescal.imag.fr/membres/vania.mar … ACHOS.html en cours c’était très intéressant.

MacOSX est écris en C, C++ et Objective-C, je pense que le C reste comme dette technique de Next.

Pourquoi ? Avec le C++ tu gère toi même ta mémoire ce qui est le seul pré-requis pour faire un système d’exploitation (et encore…).

Un gros fasciste est à la tête du développement de ce logiciel ?

Enfin là on parle d’écrire un kernel, utiliser des appels systèmes ça se fait dans tout les langages et utiliser des wrappers en espace utilisateur pour le faire ça se fait même pour le C (printf utilise l’appelle système write par exemple).

Très franchement je pense que ce prendre la tête sur les langages est dommage d’une part, mais en plus est hors de sujet.

Le C est la lingua franca en la programmation informatique pour une raison en particulier : l’ABI et les conventions d’appel sont clairement spécifiées.
A contrario le C++ est moins bien spécifié sur ces points (chaque compilateur en fait à sa tête et même différentes versions d’un même compilateur ne sont pas forcément compatibles entre elles).
C’est la seule raison technique valable (mais elle est de taille) pour préférer le C au C++ lors de l’écriture du kernel.

Comme l’a dit MisterFreez, MacOS utilise du C et du C++ pour la partir système, et de l’Objective-C pour les API utilisateur. Chose peut-être moins connue, Windows utilise du C++ en interne, beaucoup d’APIs sont juste des wrappers C autour d’objets C++ (encore une fois, pour des questions d’ABI / CC).
Un mythe que les détracteurs du C++ se font un plaisir de répandre, c’est que toutes les fonctionnalités objet rendent le langage plus lourd à l’exécution. Mais c’est tout simplement faux : en C++ on ne paye que pour ce qu’on utilise.

Exemple : si une classe n’a pas de méthodes virtuelles, tu n’auras pas de VTable associée, donc pas de RTTI (puisque ça se base sur le même mécanisme, cf. la spécification de dynamic_cast 5.2.7-6) ce qui rend ta classe strictement équivalente à une struct C dont chaque méthode reçoit un pointeur vers l’objet en premier paramètre.
Autre exemple, les exceptions sont généralement implémentées avec des tables séparées, ce qui fait que si aucune exception n’est levée lors de l’exécution alors y’aura rien à payer. Windows utilise en plus des SEH sur la pile (ce qui permet aussi aux programmes C de traiter les exceptions en provenance du système), mais c’est tellement léger que c’est totalement négligeable (3 mots mémoire à modifier lorsque la fonction veut utiliser les exceptions, ce qui n’est même pas obligatoire).

Bref, Torvalds est un intégriste, et j’ai beau avoir beaucoup de respect pour les produits qu’il fait, force est de constater que son approche des langages de programmation est un cas évident de syndrome du Blub.

Discussion très intéressante, j’aimerais bien avoir le début :118

Bien que totalement incompétent en programmation système, j’en profite pour ramener mon grain de sel :blush:

Un mythe que les détracteurs du C++ se font un plaisir de répandre, c'est que toutes les fonctionnalités objet rendent le langage plus lourd à l'exécution. Mais c'est tout simplement faux : en C++ on ne paye que pour ce qu'on utilise.

Si on trouve la documentation qui explique de façon détaillée le coût en temps et en mémoire de tous les usages courant en C++, alors on sait ce qu’on paye et ce n’est pas un problème. Dans le cas contraire, on ne peut pas deviner et là ça peut être dommageable. Des explications aussi concises et détaillées que celles-ci sont très appréciables :

si une classe n'a pas de méthodes virtuelles, tu n'auras pas de VTable associée, donc pas de RTTI (puisque ça se base sur le même mécanisme, cf. la spécification de dynamic_cast 5.2.7-6) 

Il doit y en avoir des centaines à connaître en C++. Cela nécessite beaucoup plus de temps pour les maîtriser que pour le C. Cependant pour de la programmation système, les développeurs sont censés être ultra-compétents. Donc pour moi le C++ est compatible avec la programmation système.


PS : Quel est le sujet de ce thread ?

Salut,

À mon avis, plutôt parce que cela n’aurait aucun intérêt de reprogrammer le noyau en C++. Sérieusement quel serait le gain comparer à un noyau écrit en C? Étant donné les contraintes que cela implique, presqu’aucune des fonctionnalités supplémentaires du C++ ne serait utilisable, on se retrouverait quasi avec du C… autant resté en C.

Si j’ai bien saisit l’idée, un programmeur ne peut pas se rendre compte de la différence de “puissance” entre les langages s’il ne connaît pas le plus “puissant” d’entre eux? C’est intéressant, mais peut-être un peu orgueilleux de la part de l’auteur puisque cela suppose qu’il connaisse le plus “puissant” langage pour avoir pu échafauder cette théorie… Également, il aurait été intéressant de spécifier ce qu’il entends par “puissance” parce qu’au final c’est une notion fort subjective.

Personnellement tout ce que je vois en le lisant c’est que c’est un mordu de Lisp qui essaye de défendre bec et ongle ce langage. C’est d’ailleurs à se demander s’il n’est pas lui-même victime du syndrome qu’il décrit :mrgreen:

[quote=“branch”]Si on trouve la documentation qui explique de façon détaillée le coût en temps et en mémoire de tous les usages courant en C++, alors on sait ce qu’on paye et ce n’est pas un problème. Dans le cas contraire, on ne peut pas deviner et là ça peut être dommageable.
[…]
Il doit y en avoir des centaines à connaître en C++.[/quote]
Il n’y a pas tant de fonctionnalités en plus dans le langage lui-même. Ça concerne principalement les deux que j’ai cité (polymorphisme et exceptions).
Par contre le C++ apporte des choses comme les templates qui sont quasi systématiquement inline et que le compilateur peut donc optimiser fortement. Par exemple les vecteurs de la STL, une fois inlinés, produisent du code similaire à des bon vieux tableaux C, la simplicité d’utilisation en plus. Si tu veux utiliser at() au lieu de [] c’est documenté : ça te coûtera un test en plus (bounds checking). Comme la plupart des différences se trouvent dans la lib standard, ça n’a pas vraiment d’intérêt de détailler le coût exact en temps/mémoire : en C si tu as besoin d’une fonctionnalité donnée, tu la codes ou tu la réutilises à partir d’une lib, tu vas pas chipoter pour ça… Si t’as envie de chipoter, tu te passes de la fonctionnalité et tu fais autrement. Bah en C++ c’est pareil.

Non, tu as compris de travers. Certains programmeurs (ceux atteints du syndrome) n’en sont pas capables, car ils rapportent tout à ce qu’ils connaissent sans essayer d’adapter leur vision des choses aux paradigmes du langage. Lisp, j’ai mis un bon moment à l’apprendre car il y avait plein de concepts que je n’avais jamais ne serait-ce qu’imaginé en C++, et pourtant dès les premières fois où j’ai eu affaire à Lisp j’ai été complètement soufflé (et j’avais déjà fait du fonctionnel avant), preuve qu’on peut très bien se situer vers le “bas de la chaîne” tout en reconnaissant ce qui se trouve “au dessus” pour ce que c’est : des concepts que l’on ne maîtrise pas encore mais qui peuvent s’avérer utiles (et ils le sont, Lisp a définitivement changé ma manière de programmer).

Comme je l’ai expliqué ça n’a rien à voir. Ce n’est pas une question de maîtrise des paradigmes, mais de savoir admettre que ce qu’on ne connaît pas n’est pas juste “quelque chose de bizarre qui est inutile parce que je sais déjà faire autrement” mais que ça peut au contraire tout à fait vouloir dire qu’on a loupé quelque chose. Loin d’être de l’orgueil c’est plutôt de l’humilité justement.
Quant à savoir quel langage est le plus puissant, c’est très dur à déterminer objectivement mais à peu près tout le monde s’accorde sur le fait que Lisp est dans le peloton de tête. :wink:

Dans le contexte, c’est la capacité d’abstraction et les outils que le langage fournit pour aider le programmeur à s’exprimer.

Ajouté en haut.

[quote=“branch”]Un mythe que les détracteurs du C++ se font un plaisir de répandre, c'est que toutes les fonctionnalités objet rendent le langage plus lourd à l'exécution. Mais c'est tout simplement faux : en C++ on ne paye que pour ce qu'on utilise.

Si on trouve la documentation qui explique de façon détaillée le coût en temps et en mémoire de tous les usages courant en C++, alors on sait ce qu’on paye et ce n’est pas un problème. Dans le cas contraire, on ne peut pas deviner et là ça peut être dommageable.[/quote]
Ça s’appelle la norme. Ce n’ai pas aussi concis que ce que viens d’énoncer syam, mais c’est plus précis et plus détaillé.

Ouai mais non. Ce n’est pas parce qu’on est un dieu dans un domaine qu’on l’ai dans un autre, même si l’un peu se lier à l’autre.

Ne pas pourrir le thread initial.

Un gros fasciste est à la tête du développement de ce logiciel ?
[/quote]

À mon avis, plutôt parce que cela n’aurait aucun intérêt de reprogrammer le noyau en C++. Sérieusement quel serait le gain comparer à un noyau écrit en C? Étant donné les contraintes que cela implique, presqu’aucune des fonctionnalités supplémentaires du C++ ne serait utilisable, on se retrouverait quasi avec du C… autant resté en C.[/quote]
Ouai il faut le dire vite. Un langage objet te permet d’avoir un bien meilleur contrôle de la visibilité des données ce qui n’est pas un mal pour ce qui est de la sécurité. Le fait d’utiliser des interfaces peut être agréable pour la gestion et la maintenance des structure de données. Enfin la gestion des types est bien plus sûr en C++ qu’en C.

[quote=“Taurre”][quote=“syam”]
Bref, Torvalds est un intégriste, et j’ai beau avoir beaucoup de respect pour les produits qu’il fait, force est de constater que son approche des langages de programmation est un cas évident de syndrome du Blub.
[/quote]

Si j’ai bien saisit l’idée, un programmeur ne peut pas se rendre compte de la différence de “puissance” entre les langages s’il ne connaît pas le plus “puissant” d’entre eux? C’est intéressant, mais peut-être un peu orgueilleux de la part de l’auteur puisque cela suppose qu’il connaisse le plus “puissant” langage pour avoir pu échafauder cette théorie… Également, il aurait été intéressant de spécifier ce qu’il entends par “puissance” parce qu’au final c’est une notion fort subjective.

Personnellement tout ce que je vois en le lisant c’est que c’est un mordu de Lisp qui essaye de défendre bec et ongle ce langage. C’est d’ailleurs à se demander s’il n’est pas lui-même victime du syndrome qu’il décrit :mrgreen: [/quote]
Tu as déjà lu des écris de Linus sur le C++ ? Quand il en parle il n’est plus serein, il s’énerve, mais ne remet pas vraiment en cause le langage. Ils dis que le C++ est très sophistiqué et que beaucoup de développeurs C++ sont des brèles et qu’il ne veut pas se retrouver avec le code de ses empafrés.

Pour vous donner un exemple de code C++ performant, il y a l’id Tech 4. Le même gars, John Carmack, a travaillé en assembleur et en C pendant 15 à 20 ans avant de passer au C++. Ça ne veut pas dire que le C++ est meilleur que le C juste que rabrouer le C++ comme le fait Torvald n’a pas de réalité objective. Cela relève de la fermeture d’esprit. Il est normal que linux reste en C, le code est trop important pour réaliser un portage.

Personnellement ma thèse n’est pas d’expliquer que tel ou tel langage est meilleur ou non à un autre. Juste que pour faire de la programmation bas niveau il faut un langage où l’on gère soit même la mémoire et qui est compilé en langage natif. Le fait de pouvoir effectuer des appels système de manière directe en C++ le rend encore plus approprié que d’autre langage comme l’ADA ou le fortran.

Pour la question des types, je ne connais pas assez bien les différences entre le C et le C++ pour me prononcer.

Par contre, j’ai un peu de mal à voir le rapport entre la visibilité des données et la sécurité. Je veux dire, cela ne sert qu’à empêcher l’utilisateur de modifier et/ou d’avoir accès à certains membres d’un objet (ou d’une structure), or je ne vois pas très bien en quoi cela est plus “sûre” que de laisser libre accès à ces derniers.

Sinon, il est possible de réduire la visibilité des données en C à l’aide des TAD (un peu radical mais efficace).

Oui, j’ai eu l’occasion de lire quelques répliques de lui concernant le choix du langage pour concevoir git.
En fait, je ne nie pas le fait que Linus Torvalds soit un intégriste, je pense que c’est assez claire. Il n’avance absolument aucun argument technique dans sa réponse et ne fait que de taper sur les programmeurs C++. Il aurait, je pense, été plus simple et plus franc de dire que le C est un langage qu’il maîtrise et apprécie et que c’est pour cette raison qu’il l’a choisit.

De ce côté, on est entièrement d’accord :wink:

Je comprends pas ce que tu veux dire avec TAD.

Je dois reconnaître que l’article de Wikipedia sur le sujet est loin d’être clair. En fait, le principe est assez simple et se comprend facilement avec un exemple:

list.h

#ifndef LIST_H
#define LIST_H

struct list;

struct list *list_create(size_t);
void list_delete(struct list *);
int list_push_front(struct list *, void *);
int list_push_back(struct list *, void *);
int list_pop(struct list *, void *);

#endif /* LIST_H */

list.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "list.h"


struct element {
	char *data;
	struct element *next;
};


struct list {
	struct element *first;
	struct element *last;
	size_t el_sz;
};



struct list *
list_create(size_t el_sz)
{
	struct list *self;

	if ((self = malloc(sizeof *self)) == NULL)
		return NULL;

	self->first = self->last = NULL;
	self->el_sz = el_sz;
	return self;
}


void
list_delete(struct list *self)
{
	struct element *it;

	for (it = self->first; it != NULL; it++) {
		struct element *tmp = it;

		it = it->next;
		free(tmp->data);
		free(tmp);
	}

	free(self);
}


static struct element *
element_create(size_t el_sz, void *data)
{
	struct element *tmp;

	if ((tmp = malloc(sizeof *tmp)) == NULL)
		return NULL;

	if ((tmp->data = malloc(el_sz)) == NULL) {
		free(tmp);
		return NULL;
	}

	memcpy(tmp->data, data, el_sz);
	tmp->next = NULL;
	return tmp;
}


int
list_push_front(struct list *self, void *data)
{
	struct element *tmp;

	if ((tmp = element_create(self->el_sz, data)) == NULL)
		return 0;

	tmp->next = self->first;
	self->first = tmp;

	if (self->last == NULL)
		self->last = tmp;

	return 1;
}


int
list_push_back(struct list *self, void *data)
{
	struct element *tmp;

	if ((tmp = element_create(self->el_sz, data)) == NULL)
		return 0;

	if (self->last != NULL)
		self->last->next = tmp;
	self->last = tmp;

	if (self->first == NULL)
		self->first = tmp;

	return 1;
}


int
list_pop(struct list *self, void *dest)
{
	struct element *tmp;

	if (self->first == NULL)
		return 0;

	tmp = self->first;
	memcpy(dest, tmp->data, self->el_sz);
	self->first = self->first->next;
	free(tmp->data);
	free(tmp);
	return 1;
}

main.c

#include <stdio.h>
#include <stdlib.h>

#include "list.h"


int
main(void)
{
	struct list *list;
	int n;

	if ((list = list_create(sizeof (int))) == NULL)
		return EXIT_FAILURE;

	for (n = 0; n < 10; ++n)
		list_push_back(list, &n);

	while (list_pop(list, &n))
		printf("%d\n", n);

	list_delete(list);
	return EXIT_SUCCESS;
}

Comme tu peux le voir, dans le fichier list.h on se contente de déclarer le type struct list. De ce fait, il est impossible d’accéder à ses champs puisque ces derniers ne sont pas connus. Par contre, dans le fichier list.c, le type est défini de sorte que les fonctions situées dans ce fichier puisse modifier la structure :wink:

C’est ce qu’on appelle un type opaque (comme le dit Wikipedia un type abstrait est une spécification pas une implémentation), également assez proche du Pimpl dans l’esprit.

Ça c’est super intéressant.

Est-ce qu’on peut aussi mettre des pointeurs de fonction dans une structure ?

Je pense à ça :

list.c

[code]struct list {
struct element * first;
struct element * last;
int (*nieme_val)(struct list *, int);
};

static int nieme_valeur(struct list * self, int n) {
/* renvoie la nieme valeur de la liste */
return 0;
}

struct liste * list_create(void) {
struct list * self;
/* initialisation de la liste */
self->nieme_val = nieme_valeur;
return self;
}[/code]

Et est-ce qu’on pourrait appeler la fonction nieme_valeur depuis le main ?

Tout à fait, mais cela implique que la définition de la structure soit connue et dans ce cas il n’y a plus d’encapsulation :wink: