Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: impi226 am 28. April 2011, 01:33
-
Hallo zusammen!
Gespannt habe ich heute das Einsteiger-Tutorial hier verfolgt. Leider bin ich dann beim Auslagern der Ausgabe-Funktion und der Clearscreen-Funktion irgendwie hängen geblieben.
Hier mein Quelltext:
#include "main.h"
void main(void)
{
clear_screen();
print_line("Hallo Welt!");
}
void clear_screen()
{
int x;
int y;
for (x = 0; x < 80; x++)
for (y = 0; y < 80; y++)
draw_character(' ', 7, 0, x, y);
}
void print_line(char string[])
{
int i;
for (i = 0; string[i] != '\0'; i++) {
draw_character(string[i], 7, 0, i, 0);
}
}
void draw_character(char c, char forecolour, char backcolour, int x, int y)
{
unsigned short attrib = (backcolour << 4) | (forecolour & 0x0F);
volatile unsigned short *where;
where = 0xB8000 + (y * 80 + x);
*where = c | (attrib << 8);
}
Die Fehlermeldung ist:
~/c-projects/dj-kernel$ make
gcc -m32 -ffreestanding -Wall -g -fno-stack-protector -nostdinc -c -o main.o main.c
main.c: In function ‘draw_character’:
main.c:32: warning: assignment makes pointer from integer without a cast
ld -melf_i386 -Ttext=0x100000 -o kernel boot.o main.o
Eine Antwort wäre sehr nett! :-)
Gute Nacht,
Daniel
P.S.: Achja und der komplette Screen ist Lila beim Ausführen... ;-)
-
volatile unsigned short *where;
where = 0xB8000 + (y * 80 + x);
Da where ja ein unsigned short Pointer ist, und du versuchst ihm einen Wert zu zuweisen, meckert GCC.
Caste den Wert rechts einfach zu einem unsigned short*
-
Also du meinst:
where = 0xB8000 + (unsigned short *)(y * 80 + x);
Fehler ist zwar weg, aber Ausgabe ist immernoch Müll. ;-)
-
Hallo,
eher so:where = (unsigned short *)(0xB8000 + (y * 80 + x));
0xB8000 ist für den Compiler auch nur eine Zahl und kein Pointer.
Das Deine Ausgabe aber nur "Müll" ist muss IMHO eine andere Ursache haben (die obige Zeile sollte eigentlich auch ohne den Cast funktionieren, nur eben nicht ohne Warnung).
War so ein Zeichen nicht eigentlich 2 Byte groß im VGA-Puffer?
Grüße
Erik
-
ein Byte fürs Zeichen, ein Byte für die Farbe
-
Moin,
was mir gerade aufgefallen ist: in clear_screen() geht deine y-for-schleife auch bis 80, es gibt aber nur 25 Zeilen
Für deinen lila-Bildschirm hab ich gerade auch keine Lösung, sorry.
Grüße,
LittleFox
-
Moin,
was mir gerade aufgefallen ist: in clear_screen() geht deine y-for-schleife auch bis 80, es gibt aber nur 25 Zeilen
Für deinen lila-Bildschirm hab ich gerade auch keine Lösung, sorry.
Grüße,
LittleFox
oh ja, stimmt, weiß auch nicht, was mich da gestern nacht geritten hat. bin in dem bereich aber auch noch newbie, aber es reizt mich halt auch diesen bereich mal ein bisschen auszuprobieren... ;-)
-
Also du meinst:
where = 0xB8000 + (unsigned short *)(y * 80 + x);
Fehler ist zwar weg, aber Ausgabe ist immernoch Müll. ;-)
hatte ich auch ausprobiert. aber vielleicht liegt es auch an meiner clear_screen-schleife. ich werde gleich mal weiterprobieren... ;-)
danke auf jeden fall!
-
Versuch mal aus
unsigned short attrib = (backcolour << 4) | (forecolour & 0x0F);
ein
unsigned char attrib = (backcolour << 4) | (forecolour & 0x0F);
ein short sind ja 16Bit (2 Byte) und das Attributbyte ist, wie der name schon sagt, 1 byte groß
EDIT: totaler unsinn, dann geht das Bitschieben nicht ... am besten ignorieren ;)
EDIT 2: vielleicht *where = c | (char)(attrib << 8);
-
where = (unsigned short *)(0xB8000 + (y * 80 + x));
Ich schlage vor:
where = ((unsigned short*) 0xb8000) + (y * 80 + x);
Man muss ja zwei Bytes weiter für jedes Zeichen, nicht nur eins.
-
where = (unsigned short *)(0xB8000 + (y * 80 + x));
Ich schlage vor:
where = ((unsigned short*) 0xb8000) + (y * 80 + x);
Man muss ja zwei Bytes weiter für jedes Zeichen, nicht nur eins.
juhuu, danke für den tipp. hat funktioniert. muss mich unbedingt nochmal mehr mit pointern und type (casting) beschäftigen, komme sonst beruflich aus der php-ecke, der schlampensprache! :-D
danke!
-
Hallo,
Ich schlage vor:where = ((unsigned short*) 0xb8000) + (y * 80 + x);
Man muss ja zwei Bytes weiter für jedes Zeichen, nicht nur eins.
Hm, da sehe ich aber nicht wo das mit den 2 Bytes vor passieren soll.
Ich hätte eher an sowas gedacht :where = (unsigned short*)( 0xB8000 + ((y * 80 + x)*2) );
Oder werden Offsets bei der Pointer-Arithmetik (nicht bei Array-Zugriffen o.ä.) immer mit der Element-Größe multipliziert?
Grüße
Erik (der gerade an seinen C-Kenntnissen zweifelt :cry: )
-
Moin,
es sind short's, keine char's
Grüße,
LittleFox
-
Oder werden Offsets bei der Pointer-Arithmetik (nicht bei Array-Zugriffen o.ä.) immer mit der Element-Größe multipliziert?
Ja. Lern C. :-P
Und Arrayzugriffe sind doch genau dasselbe. foo[x] ist das gleiche wie *(foo + x) und *(x + foo) und x[foo].
-
x[foo]? echt?
-
Hallo,
Und Arrayzugriffe sind doch genau dasselbe. foo[x] ist das gleiche wie *(foo + x) und *(x + foo) und x[foo].
Dann frage ich mich wie man überhaupt unausgerichtete Pointer erzeugen kann.
Für int* foo = (int*)0xB8000; int x = 5; ergibt foo[ x] was anderes als foo + x. Muss ja eigentlich auch weil wie sonst sollen unausgerichtete Pointer erzeugt werden? Und bei x[foo] bin ich mir nicht ganz sicher was raus kommt aber da x eben kein Pointer ist dürfte der C-Compiler da nicht einfach so irgend eine Element-Größe annehmen können also bleibt das effektiv bei char. Bei einer normalen Addition wird doch der Ergebnistyp auch fest von einem der Operatoren abgeleitet und nicht aus einer Prioritätsentscheidung gebildet.
Ich hab jetzt auf die schnelle keinen C-Compiler zur Hand, Bitte probiere das doch mal kurz aus.
Grüße
Erik
-
Falls du mich mit ausprobieren meinst, ich hab auch kein Compiler zur Hand (nur C#), bin auf Arbeit.
Aber x[Foo] könnte, wenn man x castet, wirklich sinn ergeben:
Foo = 0xB8000
X = 0x10
Foo[X] = 0xB8010 (Foo + X)
X[Foo] = 0xB8010 (X + Foo)
...
-
Du glaubst mir nicht, dass ich C kann, erik? ;)
#include <stdint.h>
#include <stdio.h>
int main(void)
{
int* x = (int*) 0xb8000;
printf("%p\n", &x[5]);
printf("%p\n", &*(x + 5));
printf("%p\n", &5[x]);
printf("%p\n", &*(5 + x));
printf("%p\n", &*(int*)((uintptr_t) x + 5));
return 0;
}
Ausgabe:
0xb8014
0xb8014
0xb8014
0xb8014
0xb8005
-
Hallo,
Du glaubst mir nicht, dass ich C kann, erik? ;)
Das hab ich nicht geschrieben (und auch nicht gedacht).
Von dem Ergebnis bin ich aber doch ziemlich entsetzt. Vor allen das Ausgabe 2 und 4 das selbe Ergebnis liefern verstehe ich nicht. Den Ergebnistyp einer Addition muss der Compiler doch aus den beteiligten Operanden ableiten und da hätte ich nicht vermutet das der Compiler da eine Art Prioritätsentscheidung über beide Operanden macht, ich hätte mit "der Typ des linken Operand wird für das Ergebnis genommen" gerechnet.
Warum liefert Ausgabe 5 ein anderes Ergebnis? uintptr_t ist doch auch ein Pointer für ein 4 Byte großes Element oder etwa nicht?
Das ist auf jeden Fall ein Grund mehr warum ich VHDL so mag, VHDL ist wenigstens recht konsequent und verlässlich in seinem Verhalten. Da könnte man nie zwei unterschiedliche Datentypen einfach so mit einander Addieren.
Grüße
Erik
-
Bei Ausgabe 2 nimmt er doch den Typen von x? Gerade deswegen entspricht es ja Ausgabe 1. Und uintptr_t ist nunmal kein Pointer, sondern ein Integer.
-
Von dem Ergebnis bin ich aber doch ziemlich entsetzt. Vor allen das Ausgabe 2 und 4 das selbe Ergebnis liefern verstehe ich nicht. Den Ergebnistyp einer Addition muss der Compiler doch aus den beteiligten Operanden ableiten und da hätte ich nicht vermutet das der Compiler da eine Art Prioritätsentscheidung über beide Operanden macht, ich hätte mit "der Typ des linken Operand wird für das Ergebnis genommen" gerechnet.
So können sich Erwartungen unterscheiden. Ich hätte immer erwartet, dass eine Addition kommutativ ist. Pointer plus Zahl oder Zahl plus Pointer gibt wieder einen Pointer - was sollte auch sonst sinnvolles rauskommen dabei?
Warum liefert Ausgabe 5 ein anderes Ergebnis? uintptr_t ist doch auch ein Pointer für ein 4 Byte großes Element oder etwa nicht?
uintptr_t ist ein Integertyp, der groß genug ist, dass man einen Pointer drin ablegen kann.
Das ist auf jeden Fall ein Grund mehr warum ich VHDL so mag, VHDL ist wenigstens recht konsequent und verlässlich in seinem Verhalten. Da könnte man nie zwei unterschiedliche Datentypen einfach so mit einander Addieren.
Naja, zwei Pointer addieren wäre noch größerer Blödsinn. ;)
-
Von dem Ergebnis bin ich aber doch ziemlich entsetzt. Vor allen das Ausgabe 2 und 4 das selbe Ergebnis liefern verstehe ich nicht. Den Ergebnistyp einer Addition muss der Compiler doch aus den beteiligten Operanden ableiten und da hätte ich nicht vermutet das der Compiler da eine Art Prioritätsentscheidung über beide Operanden macht, ich hätte mit "der Typ des linken Operand wird für das Ergebnis genommen" gerechnet.
So können sich Erwartungen unterscheiden. Ich hätte immer erwartet, dass eine Addition kommutativ ist. Pointer plus Zahl oder Zahl plus Pointer gibt wieder einen Pointer - was sollte auch sonst sinnvolles rauskommen dabei?
Kommutativität ist etwas anderes: ∀ a,b ∊ X: a + b = b + a. Da passt der Fall nicht rein, weil a und b nicht aus der selben Menge sind. Es handelt sich praktisch um zwei verschiedene +. PTR + INT ist logisch und macht Sinn.
Aber die existens von "+: INT×PTR -> PTR" ist doch fragwürdig. Ich würde bei Addition erst einmal ein Neutrales Element und ein Inverses erwarten.
5 + (char*)0 = (char*)5 ≠ 5.
5 + (char*)1 - (char*)1 = (char*)6 - (char*)1 = ? 5 ¿
Deshalb würde ich da jetzt sowohl bei 5[ x], als auch bei 5 + x einen Compilere-ERROR für angebracht halten.
-
http://en.wikipedia.org/wiki/Pointer_%28computing%29 (http://en.wikipedia.org/wiki/Pointer_%28computing%29)
-
Addition von Zeigern und Zahlenwerten hat auf jeden Fall die hier bereits beschriebenen Eigenschaften. Ihr seid hoffentlich auch alle froh, dass das so ist, denn ihr habt sicherlich schon mal Code geschrieben, der einen Zeiger inkrementiert oder dekrementiert hat.
-
Hallo,
das alles ist vermutlich der wesentliche Grund warum ich Pointer-Arithmetik immer vermeide.
Lieber mache ich einfor (uint i=0; i<length; i++) { data[i] = ???; }
als einfor (; data<end_ptr; data++) { *data = ???; }
bei Ersterem fühle ich mich einfach wohler und im Endeffekt ist es auch das was der Compiler meistens draus macht (deswegen haben moderne CPUs ja so tolle Adressierungsmodi).
Grüße
Erik (der jetzt wieder ein Grund mehr hat VHDL lieber zu haben als C)