Zum Inhalt springen

Bit - Operation in C (alte Klausur)


Empfohlene Beiträge

Geschrieben

Hi,

habe folgende Aufgabe bekommen, ob ich die wohl lösen könne.

Ihm fiel leider nichts ein ...

Erst ein mal die Aufgabenstellung:

Sie haben über eine Karte vier Lampen an Ihren Computer angeschlossen.

Zu der Karte gibt es einen Treiber mit folgenden Funktionen:


void set( unsigned char w)

unsigned char get()

Durch diese Funktion wird ein 8-Bit Datenwort zur Karte übertragen bzw. von der Karte gelesen. Das Datenwort hat dabei die folgende Bedeutung:

 7 6 5 4 3 2 1 0

 - - - - - - - - 

| | | | | | | | |

 - - - - - - - - 

 | | | | | | | |

 | | | | | | |  --- Lampe 1 ( 0=aus, 1=ein )

 | | | | | |  ----- Lampe 2 ( 0=aus, 1=ein )

 | | | | |  ------- Lampe 3 ( 0=aus, 1=ein )

 | | | |  --------- Lampe 4 ( 0=aus, 1=ein )

 | | |  ----------- Lampe 1 ( 0=nicht blinkend, 1=blinkend )

 | |  ------------- Lampe 2 ( 0=nicht blinkend, 1=blinkend )

 | ---------------- Lampe 3 ( 0=nicht blinkend, 1=blinkend )

  ----------------- Lampe 4 ( 0=nicht blinkend, 1=blinkend )

Schreiben Sie eine C-Funktion Schnittstelle und Funktionskörper), die eine einzelne Lampe ( 1 - 4 ) blinkend oder nicht blinkend einschaltet, und dabei den Zustand der anderen Lampen unverändert lässt. Hier ist nun mein Vorschlag:

# include < stdio.h >

# include < stdlib.h >


# define AUS		0

# define NICHT_BLINKEN	1

# define BLINKEN		2


unsigned char LAMPE=0;


void show( unsigned char w)

{

	int x;


	for( x=7; x > =0; x--)

		printf("%d",x);

	printf("\n");


	for( x=7; x > =0; x--)

	{

		if(w&(1 < < x))

			printf("1");

		else

			printf("0");

	}

	printf("\n\n");

}


void set( unsigned char w)

{

	LAMPE = w;

}


unsigned char get()

{

	return LAMPE;

}


void funktion( int lampe, int modus)

{

	char w=get();


	switch( lampe)

	{

		case 1:

			switch( modus)

			{

				case AUS:

					w = w & ~17;

					break;

				case BLINKEN:

					w = w | 17;

					break;

				case NICHT_BLINKEN:

					w = w | 1;

					w = w & ~16;

					break;

				default:

					break;

			}

			break;

		case 2:

			switch( modus)

			{

				case AUS:

					w = w & ~34;

					break;

				case BLINKEN:

					w = w | 34;

					break;

				case NICHT_BLINKEN:

					w = w | 2;

					w = w & ~32;

					break;

				default:

					break;

			}

			break;

		case 3:

			switch( modus)

			{

				case AUS:

					w = w & ~68;

					break;

				case BLINKEN:

					w = w | 68;

					break;

				case NICHT_BLINKEN:

					w = w | 4;

					w = w & ~64;

					break;

				default:

					break;

			}

			break;

		case 4:

			switch( modus)

			{

				case AUS:

					w = w & ~136;

					break;

				case BLINKEN:

					w = w | 136;

					break;

				case NICHT_BLINKEN:

					w = w | 8;

					w = w & ~128;

					break;

				default:

					break;

			}

			break;

		default:

			break;

	}


	set( w);

}


void main()

{

	show( LAMPE);


	funktion( 4,BLINKEN);

	show( LAMPE);


	funktion( 4,AUS);

	show( LAMPE);


	funktion( 4,NICHT_BLINKEN);

	show( LAMPE);

}

Meine Frage(n):

Kann man das so machen? Macht man das so? Ist das O.K. so?

Währe für Eure Antworten sehr dankbar.

Info's zu Bit-Operationen:

- http://www.informatik.fh-wiesbaden.de/~linn/bitoperation.htm

- http://www.edv-schaefer.de/c-kurs/bsp-operatoren.html

Geschrieben

Hi,

was hälst denn hier von:


void function( int lampe, int modus)

{

	char w = get();


	w = w|(1<<(lampe-1));

	w = w|(modus<<(lampe-1+4));


	set( w);

}

Die erste Zeile schaltet die Lampe ein,

die zweite Zeile unterscheidet den Blink Modus, macht aber im Grunde genommen nix anderes als auch nur EIN Bit in EINER Stelle zu setzen.

Geschrieben

Hi,

habe mich wohl zu früh gefreut, die zweite Zeile setzt das Bit nicht auf "0" wenn es schon auf "1" gesetzt ist :(

Und außerdem müsste man das auch noch ändern:

# define NICHT_BLINKEN 0

# define BLINKEN 1

Geschrieben

Uli´s Ansatz gefällt mir ganz gut. Allerdings ist da nur das Lampensetzen drin, man muß aber den Modus noch ausmaskieren und neu setzen und auch Jaipur hat das übersehen, deshalb klappt das so nicht.

unsigned char schalte_Lampe_ein(unsigned char lampe, unsigned char modus)

{

if (lampe>4 || lampe<1)) return 0; // wenn´s denn sein muß

set( get() &~(1<<(lampe+3)) | (1<<(lampe-1)) + (modus<<(lampe+3))); // setzen, löschen, Modus mask & Modus set auf einmal

return ( get() );

}

Da man jedoch ausgeht, daß die Lampenschaltung nur einmal existiert, könnte man ja auch mit einer static-Variable arbeiten und sich so das get() set() sparen. Bei Hardware-Adressen wird praktisch immer mit statics gearbeitet und wenn es sich nicht nur um Output-Adressen, sondern auch oder nur um Input-Adressen handelt, wird immer mutable bei der (Klassen-)Deklaration dazugefügt.

static unsigned char w=0;

void schalte_Lampe_ein(unsigned char lampe, unsigned char modus)

{

w = w&~(1<<(lampe+3)) | (1<<(lampe-1)) + (modus<<(lampe+3));

}

Geschrieben

Ist in meinem Fall vielleicht besser die Abfrage so zu machen:

if ((lampe-1)&0xfc) return 0; // wenn´s denn sein muß

weil die Lampe 1 auch die Zahl 1 darstellt.

Nein, ist auch blöd, weil dann 0 nicht abgecheckt wird... bleiben wir lieber doch beim < und > Vergleich...

Obwohl man davon ausgeht, daß man nur eine Lampe an oder ausschalten kann, die auch eine Nummer >0 hat...

=8-D

Aber mit sowas kann man sich ja sonstwie lange die Haare ausraufen, bis man keine mehr hat. Da kommt man sich vor als ob man sich über "Sein - oder nicht Sein?" frägt.

Geschrieben

Die Aufgabe ist auch nicht eindeutig gestellt.

Ich ging davon aus, dass eine Lampe angeschaltet soll in dem Zustand, in dem sie vorher gesetzt war, also blinkend oder dauernd.

Crush geht davon aus, dass dies auch noch extra zu setzen waere, usw.

Geschrieben

Sagt ja keiner was - Dein set(get())-Vorschlag war doch trotz allem sehr gut! Es stimmt aber, daß gerade bei programmtechnischen Themen die Fragestellung von den Leuten noch ein kleines wenig genauer ausgearbeitet sein könnte. Manchmal lag ich ja auch ziemlich daneben - und hab´s erst später mal mitbekommen.

Geschrieben

Hi,

wie schon erwähnt, es ist eine alte Klausur Aufgabe.

Ich denke mal das es dem Prof darauf ankommt,

ob und wie man weiß ein Bit zu setzen/löschen/prüfen.

Daher würde ich sagen das es so O.K. ist und außerdem steht in der Aufgabenstellung

nichts von AUS-Schalten, für Sachen die gelößt werden und nicht gefragt sind, gibt es auch keine Bonus-Punkt ....


void funktion( int lampe, int modus)

{

	char w = get();


	w = w|(1<<(lampe-1));


	switch( modus)

	{

		case BLINKEN:

			w |= (1<<(lampe-1+4));

			break;

		case NICHT_BLINKEN:

			w = w&~(1<<(lampe-1+4));

			break;

	}


	set( w);

}


void main()

{

	funktion( 4,NICHT_BLINKEN);

	show( LAMPE);


	funktion( 4,BLINKEN);

	show( LAMPE);


	funktion( 4,NICHT_BLINKEN);

	show( LAMPE);

}

Meine Lösung mag zwar programmtechnisch nicht 100% ' sein,

aber sämtliche Fehlerquellen zu lokalisieren sind/gehören nicht in Klausur Aufgaben.

Die funktion alleine, mit Begründung der Schnittstelle dürfte vollkommen ausreichen.

Geschrieben

Hier eine etwas andere Herangehensweise:

Wenn es schon unterschiedliche Zustandsgrößen in einem unsigned char gibt, könnte man ihnen auch Namen geben.

Etwa so:

#include <stdio.h>

#define BLINKEN 1

#define NICHT_BLINKEN 0

struct StatusFeld{

unsigned char power :4; /* 4bit fuer die Power */

unsigned char modus :4; /* und 4 fuer den Modus */

};

int anschalten(unsigned char*,int,int);

/* Wertebereich fuer lampe 1, 2, 3, 4 ( 0 bis 3 wäre schoener)*/

/* Wertebereich fuer modus 0, 1 */

int anschalten(unsigned char* pAlleLampen,int lampe,int mod){

struct StatusFeld *pbitfeld = (struct StatusFeld*) pAlleLampen;

if(lampe <1 || lampe > 4)

return 1;

if(mod !=1 && mod)

return 2;

pbitfeld->power |= 1<<(lampe- 1);

pbitfeld->modus = (mod == 0) ? pbitfeld->modus & (~(1<<(lampe- 1))) :

pbitfeld->modus | (1<<(lampe-1));

return 0;

}

int main( void ) {

unsigned char alleMeineLampen = 0; /* jaaa mach sie an! */

anschalten(&alleMeineLampen, 2, 1);

printf("%i\n",(int)alleMeineLampen);/* Ausgabe 34 => 0010 | 0010 */

anschalten(&alleMeineLampen, 3, 1);

printf("%i\n",(int)alleMeineLampen);/* Ausgabe 102 => 0110 | 0110 */

anschalten(&alleMeineLampen, 2, 0);

printf("%i\n",(int)alleMeineLampen);/* Ausgabe 70 => 0100 | 0110 */

return 0;

}

Geschrieben

Grundsätzlich kann man das so nach den Konventionen machen. ABER:

... die Bitfelder verwende ich NIE!!! Und zwar aus dem Grund, wie die Compiler das handhaben.

1. sind mehr als 32 Bit nicht möglich (bei M$) ist aber meines Wissens maschinenabhängig.

2. werden die Bitfelder durch Zwischenspeichern, verheriges durch-die-Gegend-Rotieren und erst mal Ausmaskieren extrem langsam und sind auch nicht unbedingt geschickter zu verwenden. (dazu braucht man nur mal so einen Bitfield-Zugriff im Debugger anschauen - absoluter Wahnsinn was Studio da anstellt)

3. Der Einsatz von ganzen Bytes ist wohl kaum langsamer und sogar geschickter, selbst wenn ich dann nachher noch alle Bits zusammenmaskieren müßte um sie dann auf den Port zu legen.

Ich bin ein bekennender Verfechter der Bitfield-Befehle - aber nur in C++. In ASM sieht das wieder ganz anders aus! Hier zeigt sich einfach mal wieder wie miserabel Compiler Code übersetzen. Derselbe Spaß findet auch beim Bits Rotieren statt - auch das ist nur umständlich mit unnötigen Zwischenspeicher und Ausmaskieren zu lösen und wird alles andere als maschinennah übersetzt (auch das gibt´s in nur einem ASM Befehl).

Das soll jetzt kein Aufruf sein, daß sein zu lassen. Doch es ist einfach schade zu sehen, wie kostbare Rechenzeit von schlechten Compilern verplempert wird.

Geschrieben

Mir gehts da weniger um Schnelligkeit sondern eher um Klarheit.

Das alles mag Geschmackssache sein- ich finde einen Namen pro Zustandsgröße einfach klarer und lesbarer.( Und wenns compiliert, who cares?)

Ich muß ehrlich zugeben, das ich schon 'ne Weile nicht mehr in reinem C programmiert habe- ich hatte wegen den Unterschieden zu C++ etwas Schwierigkeiten den Code fehlerfrei hinzukriege.

Meine Herangehensweise war dann auch schauen wie ichs in c++ machen würde und dann in c zu übersetzen.

Tschau

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...