[solved]Not dynamic 1600 int vs 3 static array of 16 000

Hello,

i don't understand why with malloc or new i get a 0 adress for an 1 600 integer elemnts, while with STATIC i can get 3 array of 16 000 int without problem.

Here is the code :

//#define STATIC

#ifdef STATIC
int t[16000];
int t2[16000];
int t3[16000];
#else
int *t = new int[1600];
//int t = (int)malloc(1600 * sizeof(int));
#endif

void setup() {
#ifndef STATIC
Serial.begin(115200);
Serial.println((int)t, HEX);
#endif
}

void loop() {
}

Arduino Forum > International > Français > Not dynamic 1600 int vs 3 static array of 16 000

Ici on parle français et on utilise les balises de code...

Quel Arduino avez vous ?

vous n'en allouez pas 1600 mais 16000 ce qui est beaucoup (trop sans doute)

comme vous n'utilisez pas ni t1 ni t2 ni t3 le compilateur les dégage dans la phase d'optimisation et la mémoire n'est pas allouée.

Si J'essaye de compiler cela sur un UNO

int t[16000];
int t2[16000];
int t3[16000];

void setup() {
  Serial.begin(115200);
  Serial.println((int)t, HEX);
}

void loop() {}

le compilateur me dit qu'il n'y a pas assez de mémoire

Mémore insuffisante ; consulter la page http://www.arduino.cc/en/Guide/Troubleshooting#size pour obtenir des astuces sur comment le réduire.
Erreur de compilation pour la carte Arduino Uno

Bonjour,

c'est un Arduino Uno.

J'ai aussi ce message de mémoire insuffisante en utilisant t1 ou t2 ou t3.

Est-ce le même d'allouer dans le tas un tableau statique ou avec malloc ?

Allouer à la compilation (va dans un segment réservé) ou dynamiquement (va dans le tas) n’est pas le problème - c’est la même mémoire au final que vous partagez... demandez vous Combien d’octets sont disponibles sur un Uno en SRAM et combien vous en réclamez ...

L’intérêt d’allouer dans le tas c’est qu’on peut libérer ensuite cette mémoire - c’est aussi potentiellement un souci car on peut faire ses trous dans le tas si on en abuse mais au final il faut que vous aillez assez de mémoire pour votre besoin.

Merci de votre réponse.

Avec plaisir

Uno = 2048 octets de SRAM. Demander 16000 int c’est demander 32000 octets de SRAM... on voit facilement pourquoi ça coince... et en demander trois fois cela c’est encore pire :confused:

J'ai remarqué que le nombre d'octets occupé par les variables global n'est pas détecté avec l'allocation dynamique.

Il faut alors vérifier le résultat de cette allocation dynamique.

Comment est-il possible, en cas d'échec de malloc, de ne pas entrer dans la boucle infini et de sortir du programme comme on le ferait avec exit() ?

Un break dans la loop infinie n'est pas possible.

J'ai pensé à une variable du style :

void loop(){
  if (ok){
    ...
  }
}

oui le compilateur ne reporte pas ce qui n'est pas alloué statiquement.

quand on fait un malloc() ou il faut tester que le pointeur obtenu est non NULL

char * ptr = (char *) malloc(100);
if (!ptr) {
  // erreur, l'allocation n'a pas fonctionné 
  while(true); // on meurt ici.
} else {
  // tout va bien, ptr pointe bien sur une zone réservée de 100 octets
  ...
}

Quand vous n'en avez plus besoin, faites un

free(ptr);
ptr = NULL; // pour se souvenir qu'on a dé-alloué la mémoire

pour ne pas aller dans la loop() qui boucle, il faut créer votre propre boucle infinie  while(true); // on meurt ici.

Merci pour vos conseils.

Avec le programme suivant il est impossible de savoir si l'allocation mémoire a bien eu lieu :

typedef struct
{
  const byte* a;// array
  const byte array_size;
} ST;

ST * st1 = new ST{new byte[200000]{1, 2}, 2};

void setup() {

  Serial.begin(115200);

  if (st1) {
    Serial.println("----------------");
    Serial.println((int)st1, HEX);
    for (int k = 0; k < st1->array_size; k++) {
      Serial.println((int) & (st1->a[k]), HEX);
    }
  }else{
    Serial.println("new !!");
  }
}

void loop() { }

:frowning:

Vous pouvez être sûr qu’elle n’a pas eu lieu si vous demandez 20,000 octets sur un UNO :slight_smile: :grin:

En C++ lorsqu’on fait new on devrait faire un try/catch ou spécifier de ne pas "throw-er"

try
{
    ...
}
catch(std::bad_alloc&) 
{
    ...
}

Ou alors faire un new(nothrow) ...); et tester si le pointeur est non nul mais sur les petits arduino la partie try/catch et throw est désactivée dans le compilateur donc on ne peut pas faire comme cela...

Pour une structure de base comme vous avez on s’en sort avec un malloc()

La raison pour laquelle ce n’est pas implémenté c’est que La pile de programme est copiée une fois pour le bloc try et pour chaque bloc catch. Dans le cas où le try tourne mal, la pile try-block sera rejetée et l'une des piles catch block sera exécutée... c’est trop coûteux quand vous n’avez que 2k ou 8k de SRAM...

Bonjour,

merci de votre aide et votre expertise.

Je dois alors vérifier petit à petit les résultats des malloc comme ceci :

//#define ww "Serial.println"

typedef struct
{
  const byte * a;// array of byte each from 0 to 255
  const unsigned long array_size;
} ST;

//ST * st1 = new ST{new byte[200]{1, 2}, 2};

ST * create(const unsigned long n) {
  ST * p = (ST*)malloc(sizeof(ST));
  if (p) {
    byte *b = (byte*)malloc(sizeof(byte) * n);
    if (!b) {
      free(p);
      p = NULL;
    }
    else {
      p->a = b;
      for (unsigned long l = 0; l < n ; l++) {
        *(byte *)&p->a[l] = 66;
      }
      *(unsigned long *)&p->array_size = n;
    }
  }
  return p;
}

ST * st1 = create(2);

void print_ST(ST* st1) {

  Serial.println("----------------");
  //  Serial.print("st1->array_size : ");
  //  Serial.println(st1->array_size);
//  Serial.println((int)st1, HEX);
  for (unsigned long k = 0; k < st1->array_size; k++) {
//    Serial.println((int) & (st1->a[k]), HEX);
    Serial.println(st1->a[k]);
  }
}

void initialize_ST(ST* p, const byte *b, const unsigned long n) {
  for (unsigned long k = 0; k < n; k++) {
    *(byte*)&p->a[k] = b[k];
  }
  *(long*)&p->array_size = n;
}

void setup() {

  Serial.begin(115200);
  
  if (st1) {
    print_ST(st1);
    byte a[] = {11, 22};
    byte *p = &a[0];
    initialize_ST(st1, p, sizeof(a) / sizeof(byte));
    print_ST(st1);
    free(st1);
    st1 = NULL;
  } else {
    Serial.println("malloc !!");
    while (true); // on meurt ici.
  }
}

void loop() {
  Serial.println("loop");
  delay(1000);
}

C'est ce que j'ai réussi de mieux pour initialiser la structure ST comme avec new et son initialisation directe.
Cette implémentation me semble lourde car :

  • je suis quand même obligé de créer un tableau pour initialiser le tableau de la structure
  • dans le bloc "if (st1) {" : Il semble que l'on ne puisse pas utiliser memcpy car le tableau int t[]= { 1, 2 }; disparaîtrait en sortant du bloc.

:frowning:

vous pourriez simplifier cette partie

 else {
      p->a = b;
      for (unsigned long l = 0; l < n ; l++) {
        *(byte *)&p->a[l] = 66;
      }
      *(unsigned long *)&p->array_size = n;
    }

en écrivant simplement (puisque p pointer sur une structure de type ST)

 else {
      p->a = b;
      for (unsigned long l = 0; l < n ; l++) p->a[l] = 66;
      p->array_size = n;
    }

l'initialisation du contenu des tableaux ne se fait pas sur des éléments dynamiques
vous ne pouvez pas utiliser memcpy() pour copier la structure car elle n'est pas "plate" (shallow). La structure contient un pointeur qui pointe ailleurs, donc la taille de la structure ne représente pas la taille sous jacente et les octets sont séparés en mémoire; Si vous copier une structure dans une autre, vous dupliquez le pointeur vers la mémoire allouée séparément.

Le compilateur m'interdit de faire

for (unsigned long l = 0; l < n ; l++) p->a[l] = 66;

il me donne ce message :

exit status 1
assignment of read-only location '*(p->ST::a + ((sizetype)l))'

ni même

p->array_size = n;

j'obtiens ceci :

exit status 1
assignment of read-only member 'ST::array_size'

Pensez-vous qu'il s'agisse du faille de sécurité du langage C de pouvoir modifier des constantes ?
Un programme malveillant pourrait-il parvenir à cela ?

c'est parce que vous avez dit que a ne pouvait pas être modifié en fait dans la structure à cause du const. ce n'est pas une faille, c'est qu'il respecte ce que vous lui avez dit...

le fait qu'on puisse écrire ce que l'on veut et où on veut en mémoire fait partie des forces et faiblesses du langage, oui.