OVH Cloud OVH Cloud

casting short* [4] en short[4][64] ?

31 réponses
Avatar
Bernie
Bonjour,
J'ai déjà rencontré ce prb et je l'avais solutionné de manière "batarde",
mais à force je me dis qu'il faudrait que je découvre un peu le fond du
prb....

soit une variable short* toto[4], qqsoit i toto[i] = (short*)malloc(64);
soit une fonction f déclarée par : void f(short param[4][64]);

comment caster "proprement" la variable toto pour la passer à f ?

merci d'avance ...

10 réponses

1 2 3 4
Avatar
Bernie
"James Kanze" a écrit dans le message de
news:42408d62$0$11530$
Fabien LE LEZ wrote:
On Tue, 22 Mar 2005 16:09:43 +0100, "Bernie" :

soit une variable short* toto[4], qqsoit i toto[i] (short*)malloc(64);


Je ne comprends pas bien comment tu te retrouves avec ce genre
de code dans un programme en C++.


Disons que la discussions qui s'en sont suivi, c'est un sacré
argument en faveur de std::vector:-).



He bien je me retrouve souvent devant ce type de probleme pour plusieurs
raisons qui surement toutes discutables :
* J'utilise le C++ pour la mécanique haut niveau de mes projets.
* Pour des questions de performances (appli video tps-reelles ou "pseudo"
tps-reelles), j'utilise du C et de l'asm(MMX/SSE2) à bas niveau.
* Conséquence, je suis obligé de tj gérer moi même les allocations de
données (alignement) critiques...
* Et je suis +/- obligé d'avoir dans mes objets des routines
d'acquisition/restitutiuon de données...

Enfin, pour finir, au contraire, je tente de limiter autant que faire ce peu
l'usage des container std, car si il sont simple et rapide à utiliser pour
implémenter un algo, il faut à postériori reprendre le code, pour que
celui-ci ne soit pas trop gourmand en tps et ressources. Je préfère donc me
poser le prb des ressources et velocité aussitot que possible en revenant au
C....



Avatar
Fabien LE LEZ
On Thu, 24 Mar 2005 08:26:07 +0100, "Bernie" :

* Pour des questions de performances (appli video tps-reelles ou "pseudo"
tps-reelles), j'utilise du C et de l'asm(MMX/SSE2) à bas niveau.


Pour l'assembleur, je comprends, puisqu'on peut utiliser explicitement
les capacités particulières d'un processeur donné.
Par contre, je ne vois pas bien la différence de performance entre C
et C++.

Enfin, pour finir, au contraire, je tente de limiter autant que faire ce peu
l'usage des container std, car si il sont simple et rapide à utiliser pour
implémenter un algo, il faut à postériori reprendre le code, pour que
celui-ci ne soit pas trop gourmand en tps et ressources.


Dans ce cas, il faut prendre le problème dans le bon sens : créer des
conteneurs qui répondent à tes critères.
std::vector<> est un conteneur à accès très rapide, mais qui utilise
plus de mémoire que nécessaire (c'est le prix de push_back), et
initialise systématiquement les variables contenues.

Le fichier <http://perso.edulang.com/fclc++/tableau.bricolage.zip>
contient un exemple de conteneur qui pourrait de convenir. J'ai mis le
mot "bricolage" dans le nom car son bon fonctionnement est loin d'être
garanti, et je n'ai pas le temps de tester. Mais normalement, son
usage devrait être aussi rapide et efficace que tes malloc(). Tu peux
même remplacer new[] et delete[] par malloc() et free() si ça te
chante, tant que tu n'utilises que des types de base.



--
;-)

Avatar
Bertrand Motuelle
Fabien LE LEZ wrote:
On Thu, 24 Mar 2005 08:26:07 +0100, "Bernie" :
[...]

Enfin, pour finir, au contraire, je tente de limiter autant que faire ce peu
l'usage des container std, car si il sont simple et rapide à utiliser pour
implémenter un algo, il faut à postériori reprendre le code, pour que
celui-ci ne soit pas trop gourmand en tps et ressources.


Dans ce cas, il faut prendre le problème dans le bon sens : créer des
conteneurs qui répondent à tes critères.
std::vector<> est un conteneur à accès très rapide, mais qui utilise
plus de mémoire que nécessaire (c'est le prix de push_back), et
initialise systématiquement les variables contenues.


Je ne comprend pas ces deux affirmations. Pourquoi plus de mémoire que
nécessaire ? Et si le vector contient des variables, comment celles-ci
pourraient-être non initialisées ?

Le fichier <http://perso.edulang.com/fclc++/tableau.bricolage.zip>
contient un exemple de conteneur qui pourrait de convenir. J'ai mis le
mot "bricolage" dans le nom car son bon fonctionnement est loin d'être
garanti, et je n'ai pas le temps de tester. Mais normalement, son
usage devrait être aussi rapide et efficace que tes malloc(). Tu peux
même remplacer new[] et delete[] par malloc() et free() si ça te
chante, tant que tu n'utilises que des types de base.


J'y ai jeté rapidement un oeil et il me semble que cette implémentation
initialise systématiquement les variables contenues (et plutôt deux fois
qu'une pour le constructeur/Resize prenant une valeur initiale).
Et je n'ai pas compris l'interêt des Resize.
Je pense que l'utilisation de vector serait plus efficace.

a+,
Bertrand.


Avatar
Fabien LE LEZ
On Thu, 24 Mar 2005 20:40:35 +0100, Bertrand Motuelle
:

std::vector<> est un conteneur à accès très rapide, mais qui utilise
plus de mémoire que nécessaire (c'est le prix de push_back), et
initialise systématiquement les variables contenues.


Je ne comprend pas ces deux affirmations. Pourquoi plus de mémoire que
nécessaire ?


Si un vector<> a alloué de la place pour 1000 éléments, et que tu
insères un 1001è élément, il va devoir allouer plus de mémoire, puis
transférer les éléments contenus vers le nouveau bloc alloué. Pour
éviter que ça n'arrive trop souvent, il va allouer tout de suite assez
de place pour 1414 éléments, histoire de voir venir.

Et si le vector contient des variables, comment celles-ci
pourraient-être non initialisées ?


On parle ici de tableaux contenant des types de base (cf sujet du
thread).
Or, un type de base n'a ni constructeur, ni valeur par défaut. En
d'autres termes, le code

short n;

est parfaitement valide, mais il n'est pas possible de prévoir la
valeur de n. L'avantage (rarement sensible, mais ça semble important
ici) est qu'on évite une écriture en mémoire.

J'y ai jeté rapidement un oeil et il me semble que cette implémentation
initialise systématiquement les variables contenues


Si les valeurs contenues sont des short, non.

Et je n'ai pas compris l'interêt des Resize.


Pas grand intérêt, il est vrai, à part de faciliter l'initialisation
différée (du tableau, pas des éléments à l'intérieur).

Je pense que l'utilisation de vector serait plus efficace.


Mon code (qui, je le rappelle, n'est pour l'instant guère plus qu'un
vague bricolage) a au moins un avantage sur vector<> : il alloue
exactement la mémoire nécessaire, pas plus. Quand tu as un tableau
dont la taille représente une proportion importante de la quantité de
RAM, ce n'est pas négligeable.
Bien sûr, il faut connaître à l'avance le nombre d'éléments.


--
;-)


Avatar
Bertrand Motuelle
Fabien LE LEZ wrote:
On Thu, 24 Mar 2005 20:40:35 +0100, Bertrand Motuelle
:

std::vector<> est un conteneur à accès très rapide, mais qui utilise
plus de mémoire que nécessaire (c'est le prix de push_back), et
initialise systématiquement les variables contenues.


Je ne comprend pas ces deux affirmations. Pourquoi plus de mémoire que
nécessaire ?


Si un vector<> a alloué de la place pour 1000 éléments, et que tu
insères un 1001è élément, il va devoir allouer plus de mémoire, puis
transférer les éléments contenus vers le nouveau bloc alloué. Pour
éviter que ça n'arrive trop souvent, il va allouer tout de suite assez
de place pour 1414 éléments, histoire de voir venir.


Ok si push_back est utilisé (voir plus bas).


Et si le vector contient des variables, comment celles-ci
pourraient-être non initialisées ?


On parle ici de tableaux contenant des types de base (cf sujet du
thread).


Ok, mea culpa, j'aurais dû suivre le thread. Mais je doute que le coût
de l'initialisation soit significatif comparé au coût de l'allocation.

[...]

J'y ai jeté rapidement un oeil et il me semble que cette implémentation
initialise systématiquement les variables contenues


Si les valeurs contenues sont des short, non.


Re-ok.

[...]

Je pense que l'utilisation de vector serait plus efficace.


Mon code (qui, je le rappelle, n'est pour l'instant guère plus qu'un
vague bricolage) a au moins un avantage sur vector<> : il alloue
exactement la mémoire nécessaire, pas plus. Quand tu as un tableau
dont la taille représente une proportion importante de la quantité de
RAM, ce n'est pas négligeable.
Bien sûr, il faut connaître à l'avance le nombre d'éléments.


Là je ne te suis pas: pourquoi penses-tu que
vector<short> vec(200);
allouerait plus que necessaire?

Le standard n'interdit pas que le vector alloue XYZ Mo, mais je serais
surpris qu'une implémentation alloue plus que demandé.
Il y aura sur-consommation mémoire si l'on étend le vector de facon
dynamique.

a+,
Bertrand.



Avatar
Loïc Joly
Si un vector<> a alloué de la place pour 1000 éléments, et que tu
insères un 1001è élément, il va devoir allouer plus de mémoire, puis
transférer les éléments contenus vers le nouveau bloc alloué. Pour
éviter que ça n'arrive trop souvent, il va allouer tout de suite assez
de place pour 1414 éléments, histoire de voir venir.


Il peut allouer ce qu'il veut, tant que ça suit une croissance
géométrique, le coefficient ne vaut pas forcément sqrt(2)


[...]


On parle ici de tableaux contenant des types de base (cf sujet du
thread).
Or, un type de base n'a ni constructeur, ni valeur par défaut. En
d'autres termes, le code

short n;

est parfaitement valide, mais il n'est pas possible de prévoir la
valeur de n. L'avantage (rarement sensible, mais ça semble important
ici) est qu'on évite une écriture en mémoire.


Oui, n n'est pas initialisé ici, mais par contre, vector<short> v(10)
initialise ses éléments à 0. Il suffit de voir le prototype du
constructeur :

explicit vector(size_type n, const T& value = T(),const Allocator& =
Allocator());

Or, T() pour un short vaut 0.

Pour ne pas initialiser les valeurs, la manière classique est :

vector<short> v;
v.reserve(1000);
v.push_back(314);
v.push_back(42);
v.push_back(151);
...


--
Loïc

Avatar
kanze
Loïc Joly wrote:
Si un vector<> a alloué de la place pour 1000 éléments, et
que tu insères un 1001è élément, il va devoir allouer plus
de mémoire, puis transférer les éléments contenus vers le
nouveau bloc alloué. Pour éviter que ça n'arrive trop
souvent, il va allouer tout de suite assez de place pour
1414 éléments, histoire de voir venir.


Il peut allouer ce qu'il veut, tant que ça suit une croissance
géométrique, le coefficient ne vaut pas forcément sqrt(2)


Il me semble avoir lu cependant que selon certains critères,
sqrt(2) est le facteur idéal. Ce qui est certain, c'est qu'avec
un facteur de 2 (qui était le facteur le plus fréquent au
début), la somme des tailles des blocs libérés ne suffirait
jamais à une nouvelle allocation ; pour tout multiple
strictement inférieur à 2, on y arrivera éventuellement.

À vrai dire, je ne vois pas l'intérêt de sqrt(2) quand 1,5 se
calcule beaucoup plus facilement (n += n >> 1), et a à peu près
le même comportement.

[...]

On parle ici de tableaux contenant des types de base (cf
sujet du thread). Or, un type de base n'a ni constructeur,
ni valeur par défaut. En d'autres termes, le code

short n;

est parfaitement valide, mais il n'est pas possible de
prévoir la valeur de n.



Selon la norme, il n'est même pas possible de lire ou de copier
n. Tout ce qu'on peut faire, c'est de lui affecter une valeur.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Falk Tannhäuser
wrote:
Loïc Joly wrote:
Il peut allouer ce qu'il veut, tant que ça suit une croissance
géométrique, le coefficient ne vaut pas forcément sqrt(2)


Il me semble avoir lu cependant que selon certains critères,
sqrt(2) est le facteur idéal. Ce qui est certain, c'est qu'avec
un facteur de 2 (qui était le facteur le plus fréquent au
début), la somme des tailles des blocs libérés ne suffirait
jamais à une nouvelle allocation ; pour tout multiple
strictement inférieur à 2, on y arrivera éventuellement.


Je crois qu'il faut pour cela que le facteur soit inférieur au
"nombre d'or" (1 + sqrt(5))/2 == 1.618... mais je me ne souviens
plus des détails.

À vrai dire, je ne vois pas l'intérêt de sqrt(2) quand 1,5 se
calcule beaucoup plus facilement (n += n >> 1), et a à peu près
le même comportement.


Effectivement !

Falk


Avatar
Franck Branjonneau
Falk Tannhäuser écrivait:

wrote:
Loïc Joly wrote:
Il peut allouer ce qu'il veut, tant que ça suit une croissance
géométrique, le coefficient ne vaut pas forcément sqrt(2)
Il me semble avoir lu cependant que selon certains critères,

sqrt(2) est le facteur idéal. Ce qui est certain, c'est qu'avec
un facteur de 2 (qui était le facteur le plus fréquent au
début), la somme des tailles des blocs libérés ne suffirait
jamais à une nouvelle allocation ; pour tout multiple
strictement inférieur à 2, on y arrivera éventuellement.


Je crois qu'il faut pour cela que le facteur soit inférieur au
"nombre d'or" (1 + sqrt(5))/2 == 1.618... mais je me ne souviens
plus des détails.


Les détails, pour autant que je sache : la n+1 ème allocation doit
demander un bloc d'une taille inférieure (ou égale) à la somme des n-1
blocs libérés ; le n ème est occupé. La raison de la suite des tailles
successives du *est* phi. C'est Koenig growth factor ;), si
je ne m'abuse.

À vrai dire, je ne vois pas l'intérêt de sqrt(2) quand 1,5 se
calcule beaucoup plus facilement (n += n >> 1), et a à peu près
le même comportement.


Effectivement !


BS à écrit qu'une raison de 2 le conduisait à se passer de reserve()
dans son code...
--
Franck Branjonneau



Avatar
James Kanze
Falk Tannhäuser wrote:
wrote:


Loïc Joly wrote:



Il peut allouer ce qu'il veut, tant que ça suit une
croissance géométrique, le coefficient ne vaut pas forcément
sqrt(2)




Il me semble avoir lu cependant que selon certains critères,
sqrt(2) est le facteur idéal. Ce qui est certain, c'est
qu'avec un facteur de 2 (qui était le facteur le plus
fréquent au début), la somme des tailles des blocs libérés ne
suffirait jamais à une nouvelle allocation ; pour tout
multiple strictement inférieur à 2, on y arrivera
éventuellement.



Je crois qu'il faut pour cela que le facteur soit inférieur au
"nombre d'or" (1 + sqrt(5))/2 == 1.618... mais je me ne
souviens plus des détails.


Moi non plus. A priori, $Sigma 2^i$ vaut $s^{i+1} - 1$ ; je
m'attendrais donc à ce que le facteur de deux prend toujours
exactement un octet de trop de ce qu'il faut pour pouvoir
réutiliser. Abstraction faite des frais généraux de la gestion
de la mémoire, évidemment. Mais c'est ce qui m'a fait penser
tout facteur strictement inférieur à 2 marcherait.
Éventuellement. Mais je n'ai pas fait d'analyse détaillé pour
être sûr. (Maintenant que tu le dis, il me semble aussi avoir
entendu cette valeur.)

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34



1 2 3 4