1

Bon attention les yeux, je vais tenter d'essayer de me relancer en C, ça promet. J'ai réessayé pas plus tard qu'en ce moment-même, je dois être au degré 0 de la nullité, et je n'ai pas de bon bouquin à disposition (j'en ai un de 1000 pages, je l'ai lu, mais il y a des années ; on me le rend prochainement).

Alors, plein de questions en vrac :

- je veux faire un fichier avec des strings. Pourquoi quand je fait :
char mastring [] = "plom plom plom"

et que je lui parle de mastring dans main(), il est pas content ? Doit y a voir un problème de déclaration, non ? Mais alors, que dois-je déclarer dans main ? Un simple pointeur vers des chars ? char * ptr_of_ma_string; ?
Et après, comment faire l'affectation de al chaine à mastring dans l'autre source ?

Pour être plus clair, en asm, j'aurais eu deux fichiers source :

dans string.asm :
xdef mastring
mastring : dc.b "ajkhqdsf",0

et dans main.asm :
lea.l mastring(pc),a0

On fait comment en Chinois ?
Ca parait over con comme question. grin


Au fait, on fait comment pour dire au compilateur de faire une table de saut pc-relative ?

2

Doit y a voir un problème de déclaration, non ?

Oui. Il faut soit que tu #include le fichier qui contient les strings, soit que tu déclares les strings dans un troisième fichier inclus par le source principal. Cette deuxième solution étant préférable si tu comptes faire plusieurs fichiers source.
(pour ne pas faire #include des strings dans les fichiers source - avec TIGCC/GCC4TI qui comporte un mergeur de constantes, ça n'aura pas de conséquences sur la taille, mais sur la plupart des environnements de développement, il n'y en a pas, donc ce n'est pas une bonne habitude à prendre).
Et après, comment faire l'affectation de al chaine à mastring dans l'autre source ?

Une string étant un pointeur, si tu veux accéder directement à la chaîne, il suffit de déclarer un pointeur:
char * toto = mastring;
Pour copier une string, c'est strcpy.
Au fait, on fait comment pour dire au compilateur de faire une table de saut pc-relative ?

Avec "-mpcrel -Wa,-l", le compilo utilisera des ea PC-relatifs, dans la mesure du possible (par exemple: jsr, bsr, lea et en ea source pour les instructions data movement, mais pas en ea destination pour les instructions data movement).
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

3

Lionel Debroux (./2) :
soit que tu déclares les strings dans un troisième fichier inclus par le source principal. Cette deuxième solution étant préférable si tu comptes faire plusieurs fichiers source.

C'est un simple header en fait ? grin
Concrètement, je mets ça dans un header :
char * mastring;

et après, j'inclus le header partout où je passe ?

Lionel Debroux (./2) :
Avec "-mpcrel -Wa,-l", le compilo utilisera des ea PC-relatifs, dans la mesure du possible (par exemple: jsr, bsr, lea et en ea source pour les instructions data movement, mais pas en ea destination pour les instructions data movement).

Ok. En fait, c'était pas exactement le sens de ma question, mais je me suis mal expliqué.

Je veux faire ça :
str1 : "abc",0
str2 : "abc",0
str3 : "abc",0

table :
dc.w label-str1
dc.w label-str1
dc.w label-str1

et dans le source :
move.w table(pc,d0.w),d0
jsr label(pc,d0.w)
label:
etc...


J'ai besoin de ce genre de table. Faut que je fasse un tableau foutu comment en C poru arriver à ce résultat ? En bref, je veux pas d'adresses relogées.

4

strings.c:
char *string1 = "ABCDE";
char *string2 = "FGHIJ";

strings.h:
extern char *string1, *string2;
main.c:
#include "strings.h"
void main() {
    printf("%s %s", string1, string2);
}
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

5

Ok, merci. Au fait, le extern sert à quoi ? A dire que la variable n'est pas locale à un seul source ?

Et y a-t-il un type BOOL ou assimilé ?

6

Et ça veut dire quoi "Initialization discards qualifiers from pointer target type" ? En faisant pile oilp ce que tu m'as écrit ? t1 c'est compliqué le C sick

7

(merci Brunni pour l'explication plus claire que la mienne grin)
"Initialization discards qualifiers from pointer target type"

C'est par exemple quand on assigne une chaîne constante (de type const char *) à un char*, et que ce warning est activé.
Pour corriger cela, soit tu déclares ton pointeur const char * (si tu ne veux pas modifier le contenu de la chaîne), soit tu fais
char *string1 = (char *)"ABCDE";
pour être sûr que ton code ne fasse pas de warning à cet endroit-là quand le warning est activé (parfois, tu n'as pas le choix d'activer ce warning ou pas).


Tu veux donc faire une vraie table de sauts... Je ferais ça avec
switch (val) {
case 0: retval = fonction0(...); break;
case 1: retval = fonction1(...); break;
case 2: retval = fonction2(...); break;
case 3: retval = fonction3(...); break;
default: jemeplainsparcequecanauraitpasduarriver(...); break;
}

(c'est parfois utile, mais en général, c'est une mauvaise idée d'oublier les break grin)

Si tu veux des tables de string ne générant pas de relocations, tu dois le faire à la main avec de l'ASM + de l'ASM inline avec opérandes C. De mémoire, TICT S1P6 (la version que j'ai optimisée, moins lisible) et Ice Hockey 68k sont deux programmes qui font ça.
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

8

Folco (./5) :
Ok, merci. Au fait, le extern sert à quoi ? A dire que la variable n'est pas locale à un seul source ?

GCC va compiler les fichiers .c les uns après les autres. Supposons que ton projet comporte deux fichiers (strings.c et main.c).

Si tu mets char *string1, *string2 dans strings.h et que tu inclues strings.h dans les deux fichiers, gcc va créer les variables deux fois (une fois quand il compile strings.c, une fois en compilant main.c), et quand il va créer le fichier final en collant les deux résultats, il va râler par ce que string1 et string2 sont définies deux fois.

Extern permet de dire à gcc quand il compile main.c que string1 est de type char *et qu'il est défini ailleurs. La variable n'est créée qu'avec strings.c, et donc on pourra recoller les deux morceaux sans problème.

Et y a-t-il un type BOOL ou assimilé ?

Non ^^
mais en général, 0 == FALSE, > 0 == TRUE
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

9

Pour le type bool tu peux écrire un truc du genre:
typedef enum {false=0, true=1} bool;
Mais ce n'est pas forcément optimal étant donné qu'on ne sait pas la taille que le compilo réservera à l'enum. Donc ça peut très bien être 32 bits, à vérifier avec sizeof(bool). Sinon une autre solution:
typedef unsigned char bool;
enum {false=0, true=1};

Ainsi en déclarant un bool tu déclares en fait un unsigned char (8 bits) et ensuite tu utilises des constantes de l'énumération que tu définis après.
Concernant le warning je n'étais pas au courant, ça fait longtemps que je n'ai plus codé sur TI sad
Une table de saut se fait soit avec un switch (mais vérifie le code qu'il te génère, ça peut être plus dégueulasse qu'autre chose), soit avec des fonctions. Par exemple (bidon):
// Définit qu'un cri est une fonction prenant 0 paramètre
typedef void (*cri_t)();

void criChien() { printf("Waf"); }
void criChat()  { printf("Miaou"); }

cri_t cris[] = {criChien, criChat};
const char *textesCris[] = {"chien", "chat"};

void main() {
    int i;
    printf("Sélectionnez un animal:\n");
    for (i = 0; i < 2; i++)
        printf("  - %s\n", textesCris[i]);
    scanf("%i", &i);
    // Saute à la bonne fonction
    cris[i]();
}

Par contre il y a un certain overhead niveau fonction, surtout sur 68k. Autant sur d'autres plate-formes tu as vraiment avantage de faire comme ça, autant là c'est à toi de voir ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

10

Lionel Debroux (./7) :
Si tu veux des tables de string ne générant pas de relocations, tu dois le faire à la main avec de l'ASM + de l'ASM inline avec opérandes C

C'est justement ça que je veux éviter, l'inline, sinon je reste 100% asm ^^

Flanker -> merci, là c'est trèc clair. top*
Brunni (./9) :
cris[ i ]();

Ah c'est aussi simple que ça ? Mais je regarderai le code, si il pète pas trop les yeux. C'est trop beau pour être vrai. Pour le coup, c'est aussi simple que les indirections en basic. grin

11

rararharhahrahrharhahr Je veux écrire ça :
dc.b "amqldjkf",0
dc.b "toeigj",0
dc.b 0
On fait comment ? A part "amqldjkf\0toeigj\0\0" ? Je voudrais évidemment écrire ça de manière lisible ...

12

Bah c'est simple en C mais c'est également simple en ASM. En ARM en mettant que tu as l'index dans r0 alors c'est juste ça:
mov lr, pc
ldr pc, [cris, r0, asl #2]

+ 1 un bx lr dans la fonction. Au total 4 cycles s'il n'y a pas de cache miss, c'est pour ça que je disais que c'est largement plus intéressant que de l'inline car il n'y a pas de restriction de taille du handler, mais sur 68k c'est une autre affaire...
A toi de voir ce que tu préfères, mais une véritable table de saut au sens goto cris[ i ] n'est pas possible en C.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

13

Pour ton deuxième problème la manière propre de faire est celle que tu as décrite. De toute manière ce n'est pas vraiment utile de faire comme tu le fais, si tu veux un tableaux d'éléments managés par le compilo alors tu le laisses faire. Il sera assez intelligent pour les placer à la suite, par contre tu vas passer par une indirection plutôt qu'un move + add + fetch en mettant que tu as calculé à l'avance les emplacements des 0 dans ta chaîne.
Tu peux faire ça assez proprement en C de toute façon:
const char *texte = "chaine1\0chaine2\0chaine3";
const char *texte1 = texte, texte2 = texte1 + 8, texte3 = texte2 + 8;

Ce qui est équivalent à (pardonne-moi la syntaxe pourrie, je connais pas bien le 68k et ça fait longtemps que je m'y étais intéressé en plus):
texte:
    dc.b "chaine1",0
    dc.b "chaine2",0
    dc.b "chaine3",0

    ; crée 3 pointeurs dans a0 à a2
    move.l #texte, a0
    move.l #(texte + 8), a1
    move.l #(texte + 16), a2
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

14

Brunni (./13) :
en mettant que tu as calculé à l'avance les emplacements des 0 dans ta chaîne.

Tu parles d'un truc maintenable et source d'erreurs toi grin
const char *texte = "chaine1\0chaine2\0chaine3";

Nan sérieux, ya pas mieux que ces deux solutions crades ?? sad

15

Brunni (./4) :
strings.c:
char *string1 = "ABCDE";
char *string2 = "FGHIJ";

strings.h:
extern char *string1, *string2;
main.c:
#include "strings.h"
void main() {
    printf("%s %s", string1, string2);
}

Ca marche en mettant un const dans le header et un dans le source. smile

16

Le code de ./9 génère des relocations wink
./11: pour les tableaux de strings sans relocations, fais un tour dans TICT S1P6 et Ice Hockey 68k wink
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

17

Okok. tongue

Bon, comment écrire maintenant la déclaration d'une fonction prenant l'adresse de mon fameux tableau en argument ?

void MaFonction (const char *Tableau);
?

Et pour l'appeler, je ferai MaFonction(TableauNuméroX) ?

En tout cas, pour la déclaration, il doit y avoir merdance, vu qu'il me dit qu'il expecte un identifier ou '(' before le token '{' grin

18

C'est pas normal, poste tout le code ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

19

Ben la déclaration marche, en effet.
Alors déjà, "tout le code", ça tient en trois lignes grin


Alors, dans vars.h, j'ai ça :
extern const char *RootMenu;
funcs.h :
extern void DrawMenu(const char *Menu)

et dans menu.c :
#include <tigcclib.h>
#include	"funcs.h"
#include	"vars.h"

void DrawMenu(const char *Menu);
{
Menu=Menu+1; //même si ça veut rien dire, c'est pour virer un warning
}
DrawMenu(RootMenu);

Je te raconte pas la volée d'erreurs et de ouarningues que je me prends ^^
C'est lourd de savoir à fond comment marche une machine, et de pas savoir lui parler en langage de haut niveau. mur Que ne fais-je pas bien ? Je dois déclarer DrawMenu en double peut-être ? A l'inclusion du header lors de l'écriture de son code ?

Au fait, une fonction déclarée je ne sais où, elle est toujours "extern" ?

20

Heu tu aurais le même problème en ASM là hein. Le programme commence forcément qqpart, et là ok ça s'appelle pas ORG mais main... tongue
Bref il te faut une fonction main comme je l'ai faite dans mes exemples.
Pour les erreurs c'est normal vu comment est défini le langage. Au top-level tu n'es pas censé avoir d'instruction donc machin va essayer de te reconnaître ça comme des déclarations à la K&R et tu vas te chopper plein d'erreurs que tu ne comprends pas.
Une règle: en C ne lis que la première erreur. Les autres sont du bullshit. Corrige-la et recompile wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

21

J'ai une fonction main, dans un autre source.

22

Ca n'empêche, tu ne peux pas mettre du code en dehors d'une fonction pour les raisons que je t'ai données. En C, tout code doit se situer dans une fonction.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

23

Ok ! J'ai donc modifié et écrit ça :
#include <tigcclib.h>
#include	"funcs.h"
#include	"vars.h"

void DrawMenu(const char *Menu)
{
Menu=Menu+1; //même si ça veut rien dire, c'est pour virer un warning
}

void Draw (void);
void Draw()
{
DrawMenu(RootMenu);
}

Et effectivement, je n'ai plus d'erreur ! Pourquoi dois-je remettre void quand j'emploie Draw() ?

24

Bon, j'oserais presque dire que j'avance à grands pas tripo
Voici mon nouveau bout de code :
void DrawMenu(const char *Menu)
{
	short MaxLenght = 0;			//size of the greatest string
	short TmpLenght;				//size of current item
	char *ItemPtr = *Menu;			//points to the current item
	do
	{
		TmpLenght = DrawStrWidth(ItemPtr,F_4x6);
		MaxLenght = (MaxLenght>TmpLenght?MaxLenght:TmpLenght);
   //mise à jour de ItemPtr vers la chaine suivante
	} while (&ItemPtr);
}

Alors, il râle parce que "Initialization makes pointer from integer without a cast" au niveau de *ItemPtr. Une question de type sûrement, mais j'arrive pas à trouver de solution...
Je veux tout simplement que ItemPtr soit égal à Menu, ie un pointeur sur un tableau de char passé en argument. Comment faire ?

Autre chose, le while(&ItemPtr);, c'est bon ? J'ai un #0.b à la fin de mon tableau de strings (donc 2 0 à la fin de la dernière string), ça va bien s'arrêter si la chaine suivante commence par #0 ?

25

You make pointer from integer. That not good.
*Menu -> accède à ce qui est pointé par Menu, c'est-à-dire à un caractère. Et toi tu tentes d'utiliser un caractère comme pointeur (char *ItemPtr) alors il te dit que c'est sûrement une connerie, et il a raison.
Si tu veux bêtement copier le pointeur tu fais char *ItemPtr = Menu. Et pour le & c'est le contraire. Mais je pense vraiment que tu devrais - à défaut de lire un livre - potasser un peu les bases du C sur un site, parce que ça c'est des soucis qu'on t'explique assez rapidement (à ton premier scanf ^^).
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

26

Ouep, j'ai lu x fois un bouquin, mais je retiens mal la syntaxe, même si je sais farpaitement ce que je veux lui faire faire. sad

Sinon, vu le code asm généré :
DrawMenu:
	move.l %d3,-(%sp)
	move.l 8(%sp),%d3
.L2:
	move.l 200.w,%a0
	clr.w -(%sp)
	move.l %d3,-(%sp)
	move.l 1628(%a0),%a0
	jbsr (%a0)
	addq.l #6,%sp
	jbra .L2

ma condition de while est foireuse, il va toujours boucler...


Sinon j'avais bien essayé ce que tu me dis (char *ItemPtr = Menu; ), mais il me renvoie autre chose :
"Initialization discards qualifiers from pointer target type". Devant tant de mauvaise volonté de sa part, j'ai pas su laquelle de mes conneries était la moins conne ...

27

Ok, c'est while (*ItemPtr); :
DrawMenu:
	move.l %a2,-(%sp)
	move.l 8(%sp),%a2
.L2:
	move.l 200.w,%a0
	clr.w -(%sp)
	move.l %a2,-(%sp)
	move.l 1628(%a0),%a0
	jbsr (%a0)
	addq.l #6,%sp
	tst.b (%a2)
	jbne .L2
	move.l (%sp)+,%a2
	rts

C'est quand même pas la classe de devoir tracer de l'assembleur pour comprendre ce qu'on dit en C. triso

28

Folco (./26) :
Sinon j'avais bien essayé ce que tu me dis (char *ItemPtr = Menu; ), mais il me renvoie autre chose : "Initialization discards qualifiers from pointer target type". Devant tant de mauvaise volonté de sa part, j'ai pas su laquelle de mes conneries était la moins conne ...

Ah ok, comme d'habitude il voulait son petit "const" kivabien. L'assembleur produit est identique, je me demande pourquoi il me fait chier avec ça, c'est sûrement un bug. embarrassed

29

Tiens, c'est marrant, j'ai ajouté ça :
ItemPtr = ItemPtr + strlen(ItemPtr) + 1;
Il râle pas, alors que ItemPtr est un pointeur, et strlen un long. Ok, c'est la même taille. Je m'attendais à devoir faire un cast, c'est pas la peine. C'est normal ? (en tout cas, le code asm généré est bon).

(au passage, je tue celui qui me dit que coder en C, ça va plus vite qu'en assembleur trifouet grin)

30

Mauvaise langue tongue

C'est un warning pour t'indiquer que tu es en train d'assigner une variable pointeur avec un pointeur d'un type légèrement différent -> potentiellement dangereux, par exemple passer l'adresse d'une chaîne constante à une fonction qui est susceptible de la modifier.

Et le deuxième cas : pointeur + entier = pointeur + (taille de l'objet pointé * entier). Genre si tu pointes sur un long et que tu fais +3, ça avance le pointeur de 12 octets. (Bon là ça change rien vu que chaque caractère fait 1 octet).

Tu devrais vraiment lire le K&R pas à pas au lieu de bidouiller comme ça, le C a bien assez de pièges comme ça tongue
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo