Comme expliqué dans d'autres réponses, le code viole les règles d'aliasing de type et fait des suppositions qui ne sont pas garanties par la norme.
Si vous souhaitiez vraiment effectuer cette optimisation à la main, il s'agirait d'une méthode correcte au comportement bien défini :
long v;
for(int i=0; i < sizeof v / sizeof *A; i++) {
v = (v << sizeof *A * CHAR_BIT) + 3;
}
for(int i=0; i < sizeof A / sizeof v; i++) {
std:memcpy(A + i * sizeof v, &v, sizeof v);
}
Les hypothèses peu sûres concernant la taille des objets ont été fixées par l'utilisation de sizeof
et la violation de l'aliasing a été corrigée par l'utilisation de std::memcpy
qui a un comportement bien défini quel que soit le type sous-jacent.
Cela dit, il est probablement préférable de garder votre code simple et de laisser le compilateur faire sa magie.
Pourquoi ai-je besoin de l'opérateur de gauche ?
Il s'agit de remplir un entier plus grand avec plusieurs copies de l'entier plus petit. Si vous écrivez une valeur de deux octets s
en un grand nombre entier l
alors changement les bits restants pour deux octets (ma version corrigée devrait être plus claire sur l'origine de ces nombres magiques) alors vous aurez un entier avec deux copies des octets qui constituent la valeur s
. Cette opération est répétée jusqu'à ce que toutes les paires d'octets dans l
sont fixés à ces mêmes valeurs. Pour effectuer le décalage, vous avez besoin de l'opérateur de décalage.
Lorsque ces valeurs sont copiées sur un tableau contenant un tableau d'entiers de deux octets, une seule copie fixe la valeur de plusieurs objets à la valeur des octets de l'objet le plus grand. Comme chaque paire d'octets a la même valeur, il en va de même pour les plus petits entiers du tableau.
Pourquoi ai-je besoin d'un autre tableau de long
?
Il n'y a pas de tableaux de long
. Seul un tableau de short
.
18 votes
Je ne sais pas pourquoi il est censé être légèrement meilleur puisqu'il semble avoir comportement indéfini . S'agit-il d'une amélioration des performances ?
0 votes
Votre professeur semble supposer que
long
est 4 fois plus grand que leshort int
- ce qui n'est en aucun cas garanti par la norme (et donc erroné sur certains compilateurs, par exemple : MSVC)33 votes
Notez que v se termine par
0x3000000300000030000003L
en supposant qu'il ne déborde pas d'abord. Et ce débordement n'est que le premier problème de ce code - ce professeur devrait no enseigner le C++.42 votes
Ne vous inquiétez pas, votre compilateur ne le comprend pas non plus. Si ce code fonctionne sur une machine particulière avec un compilateur particulier, ce n'est que par accident.
5 votes
Il s'agit toujours d'une boucle for, mais d'une boucle plus petite, avec 25 itérations au lieu de 100. Cela fonctionnerait probablement si
sizeof(long)
est de 8, mais elle ne sera pas plus rapide que les méthodes standard.0 votes
Il peut ne pas fonctionner du tout en raison d'un désalignement entre le court et le long
1 votes
@MSalters if long is 64 and short is 16 bits as assumed by theacher. Il n'y a pas de dépassement de capacité à ce que je sache. Et la valeur s'avère être 0x0003000300030003 (décaler 16 bits signifie décaler 4 caractères en notation hexadécimale).
0 votes
@MSalters en fait 0x0003000300030003.
3 votes
Votre professeur travaille à partir d'un modèle mental erroné selon lequel
A
yB
pointent vers un tableau de 200 emplacements de mémoire, et queB[i]=v
est une instruction visant à attribuer à 8 de ces emplacements de mémoire les 8 octets comprenant la valeur de v.2 votes
"Les conjectures suivantes sont étayées par des arguments convaincants : - si n>=10, le temps requis pour initialiser une matrice n'est pas très important - si n<10, le temps requis pour initialiser une matrice n'est pas très important" -- points à méditer 1.1, chapitre 1, concernant la règle 1, "Write clearly-don't be too clever", le classique, The Elements of Programming Style (Les éléments du style de programmation)
0 votes
Veuillez ré-étiqueter. Il s'agit d'une question purement [C], pas [C++]. Le seul élément positif est le
cout << endl
l'enseignement, qui a une vocation littéraire rien de la problématique posée. Quoi qu'il en soit, il utilise lesfor
boucle !5 votes
@CiaPan Ce n'est pas parce qu'un extrait C++ est aussi un extrait C valide qu'il s'agit automatiquement de C au lieu de C++ ; il y a des cas où le code est valide dans les deux langages, mais a des résultats différents dans chacun d'eux (p. ex,
sizeof('a')
essizeof(int)
en C, maissizeof(char)
en C++).0 votes
@JustinTime Pour autant que je sache, l'OP n'utilise pas de
sizeof
dans le code présenté, votre raisonnement est donc tout à fait hors sujet. Il utilise cependantprintf()
qui appartient à la bibliothèque standard du langage C, et d'un logiciel de style Cmain()
déclaration. Quoi qu'il en soit, le problème principal est la superposition d'un autre type de données en coulant des pointeurs, ce qui est UB à la fois en C et en C++.0 votes
@CiaPan Où voyez-vous printf() ? C'est juste une fonction print que j'ai écrite et que j'ai oublié d'effacer.
0 votes
@Cimmerian_Perspective Vous avez raison, j'ai dû mal lire la dernière ligne. Quoi qu'il en soit, le code est purement C (à l'exception de la sortie d'une seule nouvelle ligne), et c'est l'essentiel de ce que j'ai dit.
0 votes
@CiaPan J'ai toujours déclaré le main de cette façon, je ne savais pas que c'était un truc C.
0 votes
Un ancien codeur souhaite prendre la défense d'un autre : Lorsque j'ai appris le C, un programme était censé fonctionner dans un seul environnement pour toujours. Les compilateurs changeaient rarement, les langages "jamais", le C était "mature", le C++ une rumeur, la portabilité du code un mythe. [] et * étaient synonymes. Nous connaissions notre plate-forme et nos types. Nous moulions régulièrement des pointeurs et calculions des décalages. De telles optimisations étaient significatives. (Il est "TELLEMENT triste" que @MSalters puisse gagner des points pour "ignorance et manque de respect"). Puisque "mon vieux paysage C(++)" n'existe plus et que ces techniques sont dépassées, comprenez-les, mais désapprenez-les ensuite.
0 votes
@AlanK : J'ai travaillé avec les ancien compilateur K&R. Il n'y a pas a Le compilateur K&R, mais le compilateur C original des auteurs originaux. Vous mélangez plusieurs périodes. Le langage C était peut-être stable entre C90 et C99, mais à l'époque
[]
y*
n'étaient plus synonymes (c'était vraiment un truc B, pas C). Je comprends le commentaire sur la portabilité - C n'était pas le premier langage normalisé par l'ISO, par exemple Algol l'a précédé, mais C a été le premier langage à être à la fois normalisé et utile. Tout le monde ne l'a pas réalisé et n'a pas écrit de code portable, mais il y a une longue histoire d'écriture de mauvais code.0 votes
@MSalters : Les points de la chronologie ont été pris en compte, mais vous avez oublié les miens qui étaient (1) "La qualité du code est subjective, elle dépend de l'époque, de l'environnement, etc. Il fut un temps où l'optimisation en question avait de la valeur. Mes 10 premières années en C ont été consacrées à un portage de MS C sur BTOS (mort depuis longtemps) "90% K&R + 25% amélioration MS;-)". Matériel propriétaire. J'ai écrit du "mauvais code" que je n'enseignerais pas aujourd'hui. Il a rempli sa fonction et fonctionne encore dans quelques endroits en Namibie (ciblé pour l'extinction depuis 1998;-). C'est l'informatique pour vous et c'est la raison pour laquelle nous avons des points de vue différents sur cette question. (2) Arithmétiquement (3 << 16) + 3 == 0x30003.
0 votes
Il s'agissait d'un exemple de code valable à la fois en C et en C++, @CiaPan, mais dont les résultats sont différents en C et en C++. L'intention était de dire, "Si le code fourni peut plausiblement être valide pour plusieurs langages, alors traitez-le comme le langage que le demandeur dit qu'il est. Ne lui dites pas qu'il se trompe sur le langage qu'il utilise".
0 votes
@Cimmerian_Perspective Toutes mes excuses pour la réponse tardive, mais votre code est tout à fait valide en C++.
int main() { /* ... */ }
est défini dans la norme C++ (spécifiquement,[basic.start.main/2]
) comme l'une des deux définitions demain()
que tous les compilateurs conformes sont tenus de prendre en charge, etprintf()
est un membre de la bibliothèque standard C++, fourni dans l'en-tête<cstdio>
(Je sais que vous ne l'avez pas utilisé). Qu'il soit également La validité de C n'est pas du tout pertinente.