Je m'interroge sur une construction peu orthodoxe que je dois utiliser
en C (=E0 savoir un pointeur de tableaux).
J'ai une fonction dont le prototype est =E0 peu pr=E8s le suivant :
void f(float (*tab)[N], /* reste des arguments */);
Jusque l=E0, tout va bien. Dans le main(), j'alloue "tab" =E0 l'aide des
lignes suivantes :
#define M ...
#define N ...
int main(void)
{
/* d=E9clarations ... */
float (*t)[N];
t =3D malloc(sizeof(float) * M * N);
if (t =3D=3D NULL) { /* gestion d'erreur */ }
/* ... */
f(t, ...);
return 0;
}
J'ai cherch=E9 un peu partout, demand=E9 =E0 des personnes qui =E0 ma
connaissance connaissent bien la norme, et ce code semble l=E9gal.
J'aimerais d'une part avoir confirmation, et d'autre part savoir si
quelqu'un pourrait me dire o=F9 dans la norme je peux confirmer cela.
C'est là que je tique un peu: le *M, c'est exprès ou c'est une erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N cases. Mais je veux aussi que le compilateur sache qu'il doit considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ». À la base il s'agit d'un code FORTRAN transposé en C (pour faire des choses peu avouables ici, et qui plus est totalement non conformes à la norme...).
> J'ai cherché un peu partout, demandé à des personnes qui à ma > connaissance connaissent bien la norme, et ce code semble légal.
Il me semble aussi.
> J'aimerais d'une part avoir confirmation, et d'autre part savoir si > quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
J'ai donné mon exemplaire de la norme avec le cours qui allait avec .
Bon, tant pis. J'ai cherché, mais je suis un peu perdu dedans ...
Merci pour la (prompte) réponse en tout cas ! :-)
-- Stéphane Zuckerman
On May 28, 3:15 pm, Marc Boyer <Marc.Bo...@cert.onera.fr.invalid>
wrote:
C'est là que je tique un peu: le *M, c'est exprès ou c'est une
erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N
cases. Mais je veux aussi que le compilateur sache qu'il doit
considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ». À
la base il s'agit d'un code FORTRAN transposé en C (pour faire des
choses peu avouables ici, et qui plus est totalement non conformes à
la norme...).
> J'ai cherché un peu partout, demandé à des personnes qui à ma
> connaissance connaissent bien la norme, et ce code semble légal.
Il me semble aussi.
> J'aimerais d'une part avoir confirmation, et d'autre part savoir si
> quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
J'ai donné mon exemplaire de la norme avec le cours qui allait avec .
Bon, tant pis. J'ai cherché, mais je suis un peu perdu dedans ...
C'est là que je tique un peu: le *M, c'est exprès ou c'est une erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N cases. Mais je veux aussi que le compilateur sache qu'il doit considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ». À la base il s'agit d'un code FORTRAN transposé en C (pour faire des choses peu avouables ici, et qui plus est totalement non conformes à la norme...).
> J'ai cherché un peu partout, demandé à des personnes qui à ma > connaissance connaissent bien la norme, et ce code semble légal.
Il me semble aussi.
> J'aimerais d'une part avoir confirmation, et d'autre part savoir si > quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
J'ai donné mon exemplaire de la norme avec le cours qui allait avec .
Bon, tant pis. J'ai cherché, mais je suis un peu perdu dedans ...
C'est là que je tique un peu: le *M, c'est exprès ou c'est une erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N cases. Mais je veux aussi que le compilateur sache qu'il doit considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ».
En fait, t est un pointeur sur un tableau de N float qui pointeur sur un tableau de M tableau de N float, de même que int*p = malloc( sizeof(int) * M) est un pointeur sur un int qui pointe sur un tableau.
Après, t[i], ce sera un pointeur sur un tableau de N float.
À la base il s'agit d'un code FORTRAN transposé en C (pour faire des choses peu avouables ici, et qui plus est totalement non conformes à la norme...).
Plein de bonheur j'imagine.
Marc Boyer -- Au XXIème siècle, notre projet de société s'est réduit à un projet économique...
On 2009-05-28, Stéphane Zuckerman <jenesuispasgoth@gmail.com> wrote:
On May 28, 3:15 pm, Marc Boyer <Marc.Bo...@cert.onera.fr.invalid>
wrote:
C'est là que je tique un peu: le *M, c'est exprès ou c'est une
erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N
cases. Mais je veux aussi que le compilateur sache qu'il doit
considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ».
En fait, t est un pointeur sur un tableau de N float
qui pointeur sur un tableau de M tableau de N float,
de même que
int*p = malloc( sizeof(int) * M)
est un pointeur sur un int qui pointe sur un tableau.
Après, t[i], ce sera un pointeur sur un tableau de N float.
À
la base il s'agit d'un code FORTRAN transposé en C (pour faire des
choses peu avouables ici, et qui plus est totalement non conformes à
la norme...).
Plein de bonheur j'imagine.
Marc Boyer
--
Au XXIème siècle, notre projet de société s'est réduit
à un projet économique...
C'est là que je tique un peu: le *M, c'est exprès ou c'est une erreur de frappe.
Non non, pas de typo ici, je veux bien un tableau de floats de M * N cases. Mais je veux aussi que le compilateur sache qu'il doit considérer que t[i] signifie « avancer de sizeof(float)*i*N cases ».
En fait, t est un pointeur sur un tableau de N float qui pointeur sur un tableau de M tableau de N float, de même que int*p = malloc( sizeof(int) * M) est un pointeur sur un int qui pointe sur un tableau.
Après, t[i], ce sera un pointeur sur un tableau de N float.
À la base il s'agit d'un code FORTRAN transposé en C (pour faire des choses peu avouables ici, et qui plus est totalement non conformes à la norme...).
Plein de bonheur j'imagine.
Marc Boyer -- Au XXIème siècle, notre projet de société s'est réduit à un projet économique...
Antoine Leca
Le 28/05/2009 11:23Z, Stéphane Zuckerman écrivit :
Je m'interroge sur une construction peu orthodoxe que je dois utiliser en C (à savoir un pointeur de tableaux).
Où cela ? Dans ton code, je ne vois que des matrices à 2 deux dimensions, passées comme tableaux de tableaux (et le tableau extérieur est passé comme pointeur sur le premier élément, on est en C).
J'ai une fonction dont le prototype est à peu près le suivant : void f(float (*tab)[N], /* reste des arguments */);
Jusque là, tout va bien. Dans le main(), j'alloue "tab" à l'aide des lignes suivantes : float (*t)[N]; t = malloc(sizeof(float) * M * N);
J'ai cherché un peu partout, demandé à des personnes qui à ma connaissance connaissent bien la norme, et ce code semble légal.
Ne vois pas non plus de problèmes en dehors du cas où N*M provoque un débordement non signalé, l'exemple classique étant N==M=%6 en 16 bits.
J'aimerais d'une part avoir confirmation, et d'autre part savoir si quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
6.2.5p20 (et 6.5.6) te garantit que les éléments sont tous addressables séquentiellement en mémoire, sans aucun intervalle entre eux (exactement comme en Fortran); à partir de là, un tableau de N×M float peut être considéré comme un tableau de M bleurps, un bleurp étant évidemment un tableau de N floats.
Une manière de se faciliter la vie est d'écrire typedef float bleurp[N]; void f(bleurp*tab, ... main(){ bleurp *t; t = malloc(sizeof(bleurp)*M); dont on voit bien que c'est la même chose que le code ci-dessus, mais aussi où on reconnaît bien les constructions classiques du C.
Antoine
Le 28/05/2009 11:23Z, Stéphane Zuckerman écrivit :
Je m'interroge sur une construction peu orthodoxe que je dois utiliser
en C (à savoir un pointeur de tableaux).
Où cela ? Dans ton code, je ne vois que des matrices à 2 deux
dimensions, passées comme tableaux de tableaux (et le tableau extérieur
est passé comme pointeur sur le premier élément, on est en C).
J'ai une fonction dont le prototype est à peu près le suivant :
void f(float (*tab)[N], /* reste des arguments */);
Jusque là, tout va bien. Dans le main(), j'alloue "tab" à l'aide des
lignes suivantes :
float (*t)[N];
t = malloc(sizeof(float) * M * N);
J'ai cherché un peu partout, demandé à des personnes qui à ma
connaissance connaissent bien la norme, et ce code semble légal.
Ne vois pas non plus de problèmes en dehors du cas où N*M provoque un
débordement non signalé, l'exemple classique étant N==M=%6 en 16 bits.
J'aimerais d'une part avoir confirmation, et d'autre part savoir si
quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
6.2.5p20 (et 6.5.6) te garantit que les éléments sont tous addressables
séquentiellement en mémoire, sans aucun intervalle entre eux (exactement
comme en Fortran); à partir de là, un tableau de N×M float peut être
considéré comme un tableau de M bleurps, un bleurp étant évidemment un
tableau de N floats.
Une manière de se faciliter la vie est d'écrire
typedef float bleurp[N];
void f(bleurp*tab, ...
main(){
bleurp *t;
t = malloc(sizeof(bleurp)*M);
dont on voit bien que c'est la même chose que le code ci-dessus, mais
aussi où on reconnaît bien les constructions classiques du C.
Le 28/05/2009 11:23Z, Stéphane Zuckerman écrivit :
Je m'interroge sur une construction peu orthodoxe que je dois utiliser en C (à savoir un pointeur de tableaux).
Où cela ? Dans ton code, je ne vois que des matrices à 2 deux dimensions, passées comme tableaux de tableaux (et le tableau extérieur est passé comme pointeur sur le premier élément, on est en C).
J'ai une fonction dont le prototype est à peu près le suivant : void f(float (*tab)[N], /* reste des arguments */);
Jusque là, tout va bien. Dans le main(), j'alloue "tab" à l'aide des lignes suivantes : float (*t)[N]; t = malloc(sizeof(float) * M * N);
J'ai cherché un peu partout, demandé à des personnes qui à ma connaissance connaissent bien la norme, et ce code semble légal.
Ne vois pas non plus de problèmes en dehors du cas où N*M provoque un débordement non signalé, l'exemple classique étant N==M=%6 en 16 bits.
J'aimerais d'une part avoir confirmation, et d'autre part savoir si quelqu'un pourrait me dire où dans la norme je peux confirmer cela.
6.2.5p20 (et 6.5.6) te garantit que les éléments sont tous addressables séquentiellement en mémoire, sans aucun intervalle entre eux (exactement comme en Fortran); à partir de là, un tableau de N×M float peut être considéré comme un tableau de M bleurps, un bleurp étant évidemment un tableau de N floats.
Une manière de se faciliter la vie est d'écrire typedef float bleurp[N]; void f(bleurp*tab, ... main(){ bleurp *t; t = malloc(sizeof(bleurp)*M); dont on voit bien que c'est la même chose que le code ci-dessus, mais aussi où on reconnaît bien les constructions classiques du C.
Antoine
Lucas Levrel
Le 28 mai 2009, Stéphane Zuckerman a écrit :
#define M ... #define N ...
int main(void) { /* déclarations ... */ float (*t)[N];
t = malloc(sizeof(float) * M * N);
Pourquoi pas directement float t[M][N] ?
-- LL
Le 28 mai 2009, Stéphane Zuckerman a écrit :
#define M ...
#define N ...
int main(void)
{
/* déclarations ... */
float (*t)[N];
int main(void) { /* déclarations ... */ float (*t)[N];
t = malloc(sizeof(float) * M * N);
Pourquoi pas directement float t[M][N] ?
-- LL
Antoine Leca
Le 02/06/2009 10:17, Lucas Levrel écrivit :
Le 28 mai 2009, Stéphane Zuckerman a écrit :
#define M ... #define N ...
int main(void) { /* déclarations ... */ float (*t)[N];
t = malloc(sizeof(float) * M * N);
Pourquoi pas directement float t[M][N] ?
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est dynamique ; donc on peut changer M, passer outre les limitations sur la taille de la pile, ou déplacer le code dans une fonction annexe chargée de l'initialisation, le tout sans souci.
Antoine
Le 02/06/2009 10:17, Lucas Levrel écrivit :
Le 28 mai 2009, Stéphane Zuckerman a écrit :
#define M ...
#define N ...
int main(void)
{
/* déclarations ... */
float (*t)[N];
t = malloc(sizeof(float) * M * N);
Pourquoi pas directement float t[M][N] ?
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est
dynamique ; donc on peut changer M, passer outre les limitations sur la
taille de la pile, ou déplacer le code dans une fonction annexe chargée
de l'initialisation, le tout sans souci.
int main(void) { /* déclarations ... */ float (*t)[N];
t = malloc(sizeof(float) * M * N);
Pourquoi pas directement float t[M][N] ?
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est dynamique ; donc on peut changer M, passer outre les limitations sur la taille de la pile, ou déplacer le code dans une fonction annexe chargée de l'initialisation, le tout sans souci.
Antoine
candide
Antoine Leca a écrit :
Pourquoi pas directement float t[M][N] ?
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est dynamique ; donc on peut changer M,
Certes mais la directive
#define M
du code initial suggère qu'on n'alloue pas à l'exécution.
Au demeurant, je n'ai pas précisément vu à quel niveau Stéphane (qui n'est pas vraiment un débutant en C vu ses fils sur fclc) trouvait son code problématique (un problème d'allocation dynamique ou un problème d'arithmétique des pointeurs ?).
Antoine Leca a écrit :
Pourquoi pas directement float t[M][N] ?
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est
dynamique ; donc on peut changer M,
Certes mais la directive
#define M
du code initial suggère qu'on n'alloue pas à l'exécution.
Au demeurant, je n'ai pas précisément vu à quel niveau Stéphane (qui n'est pas
vraiment un débutant en C vu ses fils sur fclc) trouvait son code problématique
(un problème d'allocation dynamique ou un problème d'arithmétique des pointeurs ?).
C'est très différent : tu demandes à allouer N*M float en pile.
A contrario, Stéphane alloue 1 pointeur en pile, et le reste est dynamique ; donc on peut changer M,
Certes mais la directive
#define M
du code initial suggère qu'on n'alloue pas à l'exécution.
Au demeurant, je n'ai pas précisément vu à quel niveau Stéphane (qui n'est pas vraiment un débutant en C vu ses fils sur fclc) trouvait son code problématique (un problème d'allocation dynamique ou un problème d'arithmétique des pointeurs ?).
Antoine Leca
Le 02/06/2009 18:03, candide écrivit :
Certes mais la directive
#define M
... peut être modifiée en
int m; #define M m
en un instant, et le reste du code devient à géométrie variable. C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher ... = malloc(2500 * 345 * sizeof(truc) ) et de changer le 2500 par 3500, parce que les résultats du code Navier-Stockes ne sont pas probants, ou parce que on peut se permettre de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
Antoine
Le 02/06/2009 18:03, candide écrivit :
Certes mais la directive
#define M
... peut être modifiée en
int m;
#define M m
en un instant, et le reste du code devient à géométrie variable.
C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher
... = malloc(2500 * 345 * sizeof(truc) )
et de changer le 2500 par 3500, parce que les résultats du code
Navier-Stockes ne sont pas probants, ou parce que on peut se permettre
de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
en un instant, et le reste du code devient à géométrie variable. C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher ... = malloc(2500 * 345 * sizeof(truc) ) et de changer le 2500 par 3500, parce que les résultats du code Navier-Stockes ne sont pas probants, ou parce que on peut se permettre de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
Antoine
Jean-Claude Arbaut
Antoine Leca wrote:
Le 02/06/2009 18:03, candide écrivit :
Certes mais la directive
#define M
... peut être modifiée en
int m; #define M m
en un instant, et le reste du code devient à géométrie variable. C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher ... = malloc(2500 * 345 * sizeof(truc) ) et de changer le 2500 par 3500, parce que les résultats du code Navier-Stockes ne sont pas probants, ou parce que on peut se permettre de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
Antoine
Pour éviter de coder les dimensions en dur, ne peut-on pas faire la chose suivante ? (en tout cas "gcc -ansi -Wall" ne crie pas)
double get(int n, int p, double t[n][p], int i, int j) { return t[i][j]; }
L'allocation peut se faire avec double (*t)[]; t = (double (*)[])calloc(n*p, sizeof(double));
PS: j'ai un doute, ça donnerait quoi dans la déclaration de t pour un tableau à 3 dimensions ?
Antoine Leca wrote:
Le 02/06/2009 18:03, candide écrivit :
Certes mais la directive
#define M
... peut être modifiée en
int m;
#define M m
en un instant, et le reste du code devient à géométrie variable.
C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher
... = malloc(2500 * 345 * sizeof(truc) )
et de changer le 2500 par 3500, parce que les résultats du code
Navier-Stockes ne sont pas probants, ou parce que on peut se permettre
de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
Antoine
Pour éviter de coder les dimensions en dur, ne peut-on pas faire
la chose suivante ? (en tout cas "gcc -ansi -Wall" ne crie pas)
double get(int n, int p, double t[n][p], int i, int j) {
return t[i][j];
}
L'allocation peut se faire avec
double (*t)[];
t = (double (*)[])calloc(n*p, sizeof(double));
PS: j'ai un doute, ça donnerait quoi dans la
déclaration de t pour un tableau à 3 dimensions ?
en un instant, et le reste du code devient à géométrie variable. C'est en fait tout l'intérêt du préprocesseur, ce genre de truc...
du code initial suggère qu'on n'alloue pas à l'exécution.
Ah bon ? tu trouves qu'il est plus facile d'aller chercher ... = malloc(2500 * 345 * sizeof(truc) ) et de changer le 2500 par 3500, parce que les résultats du code Navier-Stockes ne sont pas probants, ou parce que on peut se permettre de passer plus de temps dans les calculs matriciels ?
Et de recommencer à l'envers lorsque les résultats ne s'améliorent pas...
Antoine
Pour éviter de coder les dimensions en dur, ne peut-on pas faire la chose suivante ? (en tout cas "gcc -ansi -Wall" ne crie pas)
double get(int n, int p, double t[n][p], int i, int j) { return t[i][j]; }
L'allocation peut se faire avec double (*t)[]; t = (double (*)[])calloc(n*p, sizeof(double));
PS: j'ai un doute, ça donnerait quoi dans la déclaration de t pour un tableau à 3 dimensions ?
candide
Jean-Claude Arbaut a écrit :
Pour éviter de coder les dimensions en dur, ne peut-on pas faire la chose suivante ? (en tout cas "gcc -ansi -Wall" ne crie pas)
double get(int n, int p, double t[n][p], int i, int j) { return t[i][j]; }