[C] Eigenaardig probleem met string

Pagina: 1
Acties:
  • 116 views sinds 30-01-2008
  • Reageer

  • I386DX
  • Registratie: Juni 2002
  • Laatst online: 27-11 20:18
Ik ben bezig aan een programma voor een op ARM7-gebaseerde microcontroller. Als compiler gebruik ik de gcc compiler. (arm-elf-gcc versie 3.4.2).

Bedoeling van mijn stukje code: bestaande string inladen, opschuiven om er vervolgens een aantal tekens voor te plaatsen.
Ik had al deze nogal uitgebreide, maar in mijn ogen juiste, code geschreven:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Uart0_WriteString(av_BuildString("test"));  //routine oproepen
  
u8* av_BuildString(u8 string[])
{
 
     u8 hoog,laag,len;
     len = 0;
     while (string[len] != '\0') len++;
     len++;
     while (len > 0)
     {
       Uart0_WriteString("ding1");
        string[len+2] = string[len-1];
       Uart0_WriteString("ding2");
         len--;
       Uart0_WriteString("ding3");
     }
     HexToAscii(&hoog, &laag, adres);
    string[0] = '!';
    string[1] = hoog;
    string[2] = laag;
    Uart0_WriteString("ding4");
    return string;
}


Ik gebruik op een andere plaats van het programma al gelijkaardige code, en daar werkt het zonder problemen. In dit stukje code loopt de microcontroller vast van zodra ik schrijf naar string (ding1 is de laatste uitvoer die ik zie).
Zelfs een super eenvoudige routine als {string[0] = 'a';} (wat dan "aest" zou moeten geven) resulteert in een vastloper.
Identieke stukjes code (hulp van ander forum) met gebruikmakende van pointers of bestaande string-routines resulteren steeds in een vastloper. Zie hier niet direct wat er foutloopt, zeker omdat gelijkaardige code op een andere plaats wel werkt.
Kdacht eventueel nog aan een geheugenprobleem (geheugen vol ofzo), maar weet niet hoe dit te controleren.

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 19:51

Robtimus

me Robtimus no like you

Er is pas geleden al een soortgelijk probleem hier besproken. Het probleem is dat "test" een string constant is, en dus niet aanpasbaar.

Verder loop je met deze code al snel tegen een ander probleem aan. Je gebruikt string[len + 2], maar dat gaat 100% zeker fout als je array niet minstens 3 karakters groter is dan len.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • I386DX
  • Registratie: Juni 2002
  • Laatst online: 27-11 20:18
Die topic niet gevonden, wist ook niet direct waar te zoeken...
Bestaat er een mogelijkheid om die constante dan toch aan te passen of kan dit nooit werken?

Wat het 2de probleem betreft: is dit een probleem? Ik geef nergens een lengte op van de string, dus ik meen dat je die dan kunt verlengen zoveel je wilt? (dynamisch) Of heb ik het hier ook totaal verkeerd?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 30-11 15:10

Creepy

Tactical Espionage Splatterer

Je weet niet wat er achter die string staat in het geheugen. Dit kan prima een andere variabele zijn, of een functie, of een deel van de stack. De string die je nu meegeeft krijgt precies de ruimte die hij nodig heeft, niet meer, dus zomaar verlengen kan zeker niet (naast het feit dat het nu een constante is)

Je zult een nieuwe string moeten alloceren met genoeg ruimte voor de originele string plus de karakters die je wilt toevoegen en deze nieuwe string teruggeven nadat je alle karakters erin hebt gekopieerd.

Overigens zal een beetje C boek of tutorial je het geheugenbeheer in combinatie met array's uitleggen.

[ Voor 10% gewijzigd door Creepy op 15-05-2007 17:32 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • writser
  • Registratie: Mei 2000
  • Laatst online: 28-11 15:44
Idd. malloc een nieuwe string van de oude lengte + x, waarbij x het aantal karakters is dat je toe wil voegen. Plaats eerst de x nieuwe karakters in de array en vervolgens alle karakters van de originele string (met een while / for lus).

Onvoorstelbaar!


  • bobo1on1
  • Registratie: Juli 2001
  • Laatst online: 19-10 00:17
Wat je eigenlijk moet doen is een pointer aanmaken waar je met malloc() geheugen aan toewijst, dan kun je prima chars wijzigen met string[0] = 'a';
Alleen als je daar een string in wilt kopieren moet je een functie als strcpy gebruiken, anders wijst je pointer naar een ander adres en heb je dus weer het zelfde probleem.
Vergeet niet het geheugen vrij te geven met free() als je het niet opnieuw wilt gebruiken, anders krijg je een memory leak.

Wat ook kan is de array declaren met een vaste grootte, dan kun je ook afzonderlijke chars wijzigen, je moet nog wel strcpy gebruiken om er data in te zetten, behalve bij de declaratie.

C:
1
2
3
char string[50] = "test"; //dit werkt
string[0] = 'a'; //dit werkt ook
string = "test2"; //dit werkt niet, string is een constante pointer, daar kun je geen ander adres aan toewijzen.


C:
1
2
3
4
5
6
char *string = (char*)malloc(50); //dit werkt
strcpy(string,"test"); //dit werkt
string[0] = 'a'; //dit werkt ook

string = "test"; //dit lijkt te werken, maar:
string[0] = 'a'; //dit werkt dus niet meer

[ Voor 41% gewijzigd door bobo1on1 op 15-05-2007 21:26 ]

Impedance, a measure of opposition to time-varying electric current in an electric circuit.
Not to be confused with impotence.


  • I386DX
  • Registratie: Juni 2002
  • Laatst online: 27-11 20:18
Ok, dank. Ben weer wat slimmer geworden ;-)
Zal jullie tips proberen toepassen en zien wat het geeft.

  • The Third Man
  • Registratie: September 2001
  • Laatst online: 21:32

The Third Man

The Third Jellyfish

Misschien een n00b-vraag maar heb je op deze microcontroller wel een OS draaien? Zo nee dan lijkt me dat een truuk als malloc() niet gaat werken. Voor strcpy heb je ook nog newlib oid nodig lijkt mij. Kan er ook naast zitten hoor (geen ARM ervaring).

Normaal gesproken doe je in dat geval namelijk:
C:
1
2
3
4
5
6
7
8
9
char returnstring[50];
unsigned char i;
returnstring[0] = '!';
returnstring[1] = hoog;
returnstring[2] = laag;

for(i=0;string[i]!='\0';i++) returnstring[i+3] = string[i];

return returnstring;

Met daaromheen je andere statements natuurlijk.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 30-11 15:10

Creepy

Tactical Espionage Splatterer

Nu crasht het programma nog steed als string[] uit 48 of meer tekens bestaat. Je zult returnstring toch echt dynamisch moeten initialiseren.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • The Third Man
  • Registratie: September 2001
  • Laatst online: 21:32

The Third Man

The Third Jellyfish

Creepy schreef op donderdag 17 mei 2007 @ 12:06:
Nu crasht het programma nog steed als string[] uit 48 of meer tekens bestaat. Je zult returnstring toch echt dynamisch moeten initialiseren.
Natuurlijk maar in naked C kan dat simpelweg niet... In C++ wel natuurlijk maar sowieso zit je (op ARM neem ik aan ook) met behoorlijke beperkingen op je RAM dus wil je ook geen extreem lange strings.

Maar wil je het beveiligen dan doe je:
C:
1
2
for(i=0;i<46&&string[i]!='\0';i++) returnstring[i+3]=string[i];
returnstring[i+1]='\0';

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Lekkere Kwal schreef op donderdag 17 mei 2007 @ 01:24:
Misschien een n00b-vraag maar heb je op deze microcontroller wel een OS draaien? Zo nee dan lijkt me dat een truuk als malloc() niet gaat werken. Voor strcpy heb je ook nog newlib oid nodig lijkt mij. Kan er ook naast zitten hoor (geen ARM ervaring).
In welke mate is malloc volgens jou afhankelijk van een OS? Feit is wel dat dynamisch geheugenbeheer op een microcontroller vaak niet een optie is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Soultaker
  • Registratie: September 2000
  • Nu online
Juist wel makkelijk als er geen OS is en er geen andere processen zijn; kun je al het geheugen reserveren voor je eigen doeleinden. :Y) (Stukje I/O, stukje stack, rest in de heap.)

  • The Third Man
  • Registratie: September 2001
  • Laatst online: 21:32

The Third Man

The Third Jellyfish

farlane schreef op zondag 20 mei 2007 @ 16:46:
[...]


In welke mate is malloc volgens jou afhankelijk van een OS? Feit is wel dat dynamisch geheugenbeheer op een microcontroller vaak niet een optie is.
Inkopper: malloc zit in de C standard library, die dus niet wordt meegelinkt door de compiler. Doe je dat wel dan wordt je microcontroller niet zo micro meer.

Op zich zou je zelf een variant kunnen schrijven natuurlijk, maar dat is meer voor de die-hard dan de praktische microcontroller programmeur ;).
Soultaker schreef op zondag 20 mei 2007 @ 17:27:
Juist wel makkelijk als er geen OS is en er geen andere processen zijn; kun je al het geheugen reserveren voor je eigen doeleinden. :Y) (Stukje I/O, stukje stack, rest in de heap.)
Ja en hoe wil je daar een stukje vanaf snoepen als interrupts gaat gebruiken? En hoe weet je precies hoe groot je stack wordt? Leuk idee maar omdat er juist niemand het geheugen beheert in de microcontroller kan er dus ook niet dynamisch mee gegoocheld worden.

[ Voor 32% gewijzigd door The Third Man op 20-05-2007 22:56 ]


  • Soultaker
  • Registratie: September 2000
  • Nu online
Lekkere Kwal schreef op zondag 20 mei 2007 @ 22:53:
Inkopper: malloc zit in de C standard library, die dus niet wordt meegelinkt door de compiler. Doe je dat wel dan wordt je microcontroller niet zo micro meer.
Veel compilers voor microcontrollers hebben wel een eigen, afgeslankte C library implementatie hoor. Hangt er een beetje vanaf hoe minimaal je platform is.
Ja en hoe wil je daar een stukje vanaf snoepen als interrupts gaat gebruiken? En hoe weet je precies hoe groot je stack wordt? Leuk idee maar omdat er juist niemand het geheugen beheert in de microcontroller kan er dus ook niet dynamisch mee gegoocheld worden.
Stukje afsnoepen? Waarom moet dat? Ik zeg dat je gewoon al je geheugen vast alloceert. De grootte van je stack moet je dan inderdaad van te voren inschatten, maar die is zelfs onder gewone besturingssystemen begrensd (al zal 'ie dan wat groter zijn).

  • The Third Man
  • Registratie: September 2001
  • Laatst online: 21:32

The Third Man

The Third Jellyfish

Soultaker schreef op maandag 21 mei 2007 @ 01:42:
[...]

Veel compilers voor microcontrollers hebben wel een eigen, afgeslankte C library implementatie hoor. Hangt er een beetje vanaf hoe minimaal je platform is.
Inderdaad, meestal newlib. Maar als je echt slanke microntroller aplicaties schrijft voor controllers met 256 bytes RAM en 16k ROM dan is dat een hoop persen. Ben wel benieuwd naar voorbeelden uit de praktijk die malloc gebruiken.
Stukje afsnoepen? Waarom moet dat? Ik zeg dat je gewoon al je geheugen vast alloceert. De grootte van je stack moet je dan inderdaad van te voren inschatten, maar die is zelfs onder gewone besturingssystemen begrensd (al zal 'ie dan wat groter zijn).
Maar juist iets als char string[50] is toch vast alloceren? Als je dynamisch wilt alloceren moet je een bron van informatie hebben over welke adressen in het geheugen wel of niet 'bezet' zijn en dat kan je niet zonder memory management.

  • Soultaker
  • Registratie: September 2000
  • Nu online
Volgens mij praten we een beetje langs elkaar heen.

Zoals farlane al aangaf doet de C library memory management voor een proces, niet de OS kernel. Het enige wat het OS doet is geheugen mappen in de memory space van het proces, als antwoord op een mmap of brk call door de C library (als er meer geheugen nodig is). In een simpele embedded omgeving waarin je geen processen hebt, kun je simpelweg direct al het vrije geheugen in het data segment gooien en de C library daaruit laten alloceren. Het memory management gebeurt dus in jouw proces (door de C library) en niet door het OS.

edit:
Neemt niet weg dat het best zinnig kan zijn om statisch gealloceerde buffers te gebruiken in dit geval; ik geef alleen aan dat het best mogelijk is om dynamische allocatie te doen op een embedded platform. (Ik zag dat die ARM7 voor allerlei fancy PDA's gebruikt wordt en een MMU heeft; dan zullen er in de praktijk toch wel enigzins geavanceerde dingen mee gedaan worden.)

[ Voor 36% gewijzigd door Soultaker op 21-05-2007 02:03 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Soultaker schreef op maandag 21 mei 2007 @ 01:58:
edit:
Neemt niet weg dat het best zinnig kan zijn om statisch gealloceerde buffers te gebruiken in dit geval; ik geef alleen aan dat het best mogelijk is om dynamische allocatie te doen op een embedded platform. (Ik zag dat die ARM7 voor allerlei fancy PDA's gebruikt wordt en een MMU heeft; dan zullen er in de praktijk toch wel enigzins geavanceerde dingen mee gedaan worden.)
Er zit idd een verschil tussen de ene micro en de andere. In een PDA bijvoorbeeld zal er extern geheugen bijgeplaatst zijn, standaard heeft de gem microcontroller niet zo heel veel ( van 128 bytes tot 8K ) RAM. Waarbij die van 8K al een behoorlijk geavanceerd model is.

Met 'niet een optie' doelde ik op het feit dat dynamisch geheugen (de)allocatie allerlei administratieve zaken met zich met meebrengt waar je geen plek of tijd voor hebt.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1