Beißt sich hier die Katze in den Schwanz?



  • Hallo.

    Ich möchte ein geometrisches Octree-Verfahren programmieren. Dazu habe ich eine Variable TBBox, welche unter anderem einen Zeiger auf die ein Feld seines eigenen Typs beinhalten soll. Ich denke, darin liegt das Problem.

    Anbei der Code der Function und die Benutzerdefinierten Typen.

    Die benutzerdefinierten Variablen:

    /*Struct definition*/
    typedef struct{
    	double x, y, z;
    	unsigned long ExternalNumber;
    	double* Variables;
    	unsigned int nVariables;
    }TNode;
    
    typedef struct{
    	TNode** NodeThread;
    	unsigned long nNode;
    
    	void* SBox; /*Soll eigentlich TBBox sein... aber da macht der Compiler nicht mit*/
    
    	double XMin, XMax, XAve;
    	double YMin, YMax, YAve;
    	double ZMin, ZMax, ZAve;
    }TBBox;
    
    int SubDivide(TBBox* B){
    	unsigned long fi=0, fj=0, fk=0;
    	unsigned int iBox=0;
    	TNode*** fNodeThread = (TNode***)calloc(8, sizeof(TNode**));
    	unsigned long *fnNodes=(unsigned long*)calloc(8, sizeof(unsigned long));
    	TBBox *SB = (TBBox*)calloc(8, sizeof(TBBox));
    	TNode *N=NULL;
    
    	for(fi=0;fi<8;fi++){
    		fNodeThread[fi] = (TNode**)calloc(B->nNode, sizeof(TNode*));
    	}
    
    	for(fi=0;fi<B->nNode;fi++){
    		N = B->NodeThread[fi];
    		if(N->x>B->XAve && N->y>B->XAve && N->z>B->ZAve){ // Box 1
    			fNodeThread[0][fnNodes[0]++]=N;
    		} else if(N->x>B->XAve && N->y>B->XAve && N->z<=B->ZAve){ // Box2
    			fNodeThread[1][fnNodes[1]++]=N;
    		} else if(N->x>B->XAve && N->y<=B->XAve && N->z>B->ZAve){ // Box3
    			fNodeThread[2][fnNodes[2]++]=N;
    		} else if(N->x>B->XAve && N->y<=B->XAve && N->z<=B->ZAve){ // Box4
    			fNodeThread[3][fnNodes[3]++]=N;
    		} else if(N->x<=B->XAve && N->y>B->XAve && N->z>B->ZAve){ // Box5
    			fNodeThread[4][fnNodes[4]++]=N;
    		} else if(N->x<=B->XAve && N->y>B->XAve && N->z<=B->ZAve){ // Box6
    			fNodeThread[5][fnNodes[5]++]=N;
    		} else if(N->x<=B->XAve && N->y<=B->XAve && N->z>B->ZAve){ // Box7
    			fNodeThread[6][fnNodes[6]++]=N;
    		} else {												 // Box8
    			fNodeThread[7][fnNodes[7]++]=N;
    		}
    	}
    
    	free(B->NodeThread);
    
    	//Sort memory
    	B->NodeThread = (TNode**)calloc(B->nNode,sizeof(TNode*));
    
    	for(fj=0;fj<8;fj++){
    		B->SBox = fNodeThread[fk];
    		for(fj=0;fj<fnNodes[fi];fj++){
    			B->NodeThread[fk++]=fNodeThread[fj][fi];
    		}
    
    		switch(fj){
    			case 0: //Box 1
    				B->SBox[fj]->XMin = B->XMin; //ERROR
    				B->SBox[fj]->XMax = B->XAve; //ERROR
    			break;
    
    			case 1: //Box 2
    
    			break;
    
    			case 2: //Box 3
    
    			break;
    
    			case 3: //Box 4
    
    			break;
    
    			case 4: //Box 5
    
    			break;
    
    			case 5: //Box 6
    
    			break;
    
    			case 6: //Box 7
    
    			break;
    
    			case 7: //Box 8
    
    			break;
    
    			default: //Box 1
    				printf("ERROR in Subroutine Subdivide\n");
    
    				return 1;
    			break;
    		}
    	}
    
    	free(fNodeThread);
    
    	return 0;
    }
    

    Mein Compiler gibt für die Zeilen mit dem Kommentar //ERROR markierten Zeilen folgende Fehlermeldung aus:
    LCC: operands of = have illegal types 'void' and 'double'
    TCC: pointer expected

    Sorry, ich blicke es nicht. Ich denke, ich vergleiche ein double mit einem double.

    Ach ja, wenn ich den Befehl so schreiben:
    B->SBox[fj].XMin funktioniert es auch nicht.

    Danke für die Hilfe


  • Mod

    typedef struct{
    
        void* SBox; /*Soll eigentlich TBBox sein... aber da macht der Compiler nicht mit*/
        // ...
    }TBBox;
    

    ➡

    typedef struct TBBox{
    
        struct TBBox* SBox;    
        // ...
    }TBBox;
    

    P.S.: Der spätere Fehler ist dir klar, oder? Da du einen Zeiger auf void hast und versuchst, diesen zu dereferenzieren, bekommst du logischerweise einen void. Aber void ist kein vollständiger Typ, man kann nichts damit machen. Du versuchst aber etwas damit zu machen (hier: Du versuchst ihn wieder zu dereferenzieren). Folglich gibt's einen Compilerfehler.
    P.P.S.: Da fällt mir noch ein Fehler auf. Wenn SBox ein Zeiger auf dein struct ist (wenn du es also so machst, wie du wolltest und wie ich es dir gezeigt habe), dann ist SBox[fj] vom Typ deines structs. Das heißt, das kannst du nicht dereferenzieren. Es muss also insgesamt B->SBox[fj].XMin heißen.
    P.P.P.S.: Immer noch TCC? Nichts gegen TCC, der ist gut für das, wofür er gemacht ist. Aber dir wurde doch schon erklärt, dass du ihn für etwas nutzt, für dass der Einsatz sogar kontraproduktiv ist. Und während der Entwicklung hätte dir ein "großer" Compiler wie GCC/CLANG/MSVC auch eine deutlich aussagekräftigere Fehlermeldung gegeben. Diese Aussagen gelten auch für LCC. TCC und LCC sind Compiler zum Einsatz auf extrem limitierter Hardware. Sie sind nicht zum Übersetzen von Programmen für limitierte Hardware und sie sind erst recht nicht zum Übersetzen von Programmen auf normaler Hardware für normale Hardware gedacht. Das "ressourcenschonend" in der Beschreibung dieser Compiler bezieht sich nämlich nicht auf die erzeugten Programme, sondern auf den Compiler selbst.



  • ...das wars. Jetzt läuft die Routine, aber es tritt etwas merkwürdiges auf.

    Die Routine wird mehrfach ausgeführt. Beim zweiten Mal erzeugt der malloc Befehl einen Fehler und das Programm, welches sich sowohl mit LCC als auch TCC kompilieren lässt friert bei der Ausführung ein.

    Anbei der Code:

    /*Struct definition*/
    typedef struct{
    	double x, y, z;
    	unsigned long ExternalNumber;
    	double* Variables;
    	unsigned int nVariables;
    }TNode;
    
    typedef struct TBBox{
    	TNode** NodeThread;
    	unsigned long nNode;
    
    	struct TBBox* SBox;
    
    	double XMin, XMax, XAve;
    	double YMin, YMax, YAve;
    	double ZMin, ZMax, ZAve;
    }TBBox;
    
    int SubDividingComplette(TBBox* B, unsigned long TargetNodeNumber){
    	unsigned long fi=0, fj=0;
    	unsigned int Complette=0;
    
    	if(B->nNode>TargetNodeNumber){
    		SubDivide(B, TargetNodeNumber);
    
    		for(fi=0;fi<8;fi++){
    			if(B->SBox[fi].nNode>TargetNodeNumber){
    				SubDivide(&B->SBox[fi], TargetNodeNumber);
    				printf("%lu\n", fj++);
    			}
    		}
    
    	}
    	return 0;
    }
    
    int SubDivide(TBBox* B, unsigned long TNN){
    	unsigned long fi=0, fj=0, fk=0;
    	unsigned int iBox=0;
    	TNode*** fNodeThread = (TNode***)calloc(8, sizeof(TNode**));
    	unsigned long *fnNodes=(unsigned long*)calloc(8, sizeof(unsigned long));
    	TNode *N=NULL;
    	printf("1.\n");
    	TBBox *SB = (TBBox*)malloc(8*sizeof(TBBox)); //Problem
    	printf("2.\n");
    	for(fi=0;fi<8;fi++){
    		fNodeThread[fi] = (TNode**)calloc(B->nNode, sizeof(TNode*));
    	}
    
    	for(fi=0;fi<B->nNode;fi++){
    		N = B->NodeThread[fi];
    		if(N->x>B->XAve && N->y>B->XAve && N->z>B->ZAve){ // Box 1
    			fNodeThread[0][fnNodes[0]++]=N;
    		} else if(N->x>B->XAve && N->y>B->XAve && N->z<=B->ZAve){ // Box2
    			fNodeThread[1][fnNodes[1]++]=N;
    		} else if(N->x>B->XAve && N->y<=B->XAve && N->z>B->ZAve){ // Box3
    			fNodeThread[2][fnNodes[2]++]=N;
    		} else if(N->x>B->XAve && N->y<=B->XAve && N->z<=B->ZAve){ // Box4
    			fNodeThread[3][fnNodes[3]++]=N;
    		} else if(N->x<=B->XAve && N->y>B->XAve && N->z>B->ZAve){ // Box5
    			fNodeThread[4][fnNodes[4]++]=N;
    		} else if(N->x<=B->XAve && N->y>B->XAve && N->z<=B->ZAve){ // Box6
    			fNodeThread[5][fnNodes[5]++]=N;
    		} else if(N->x<=B->XAve && N->y<=B->XAve && N->z>B->ZAve){ // Box7
    			fNodeThread[6][fnNodes[6]++]=N;
    		} else {												 // Box8
    			fNodeThread[7][fnNodes[7]++]=N;
    		}
    	}
    
    	free(B->NodeThread);
    	B->NodeThread = NULL;
    
    	//Sort memory
    	B->NodeThread = (TNode**)calloc(8,sizeof(TNode*));
    
    	for(fj=0;fj<8;fj++){
    		SB[fj].NodeThread = fNodeThread[fk];
    		SB[fj].nNode = fnNodes[fj];	
    	for(fi=0;fi<fnNodes[fj];fi++){
    			B->NodeThread[fk++]=fNodeThread[fj][fi];
    		}
    
    		switch(fj){
    			case 0: //Box 1
    				SB[fj].XMin = B->XAve;
    				SB[fj].XMax = B->XMax;
    
    				SB[fj].YMin = B->YAve;
    				SB[fj].YMax = B->YMax;
    
    				SB[fj].ZMin = B->ZAve;
    				SB[fj].ZMax = B->ZMax;
    			break;
    
    			case 1: //Box 2
    				SB[fj].XMin = B->XAve;
    				SB[fj].XMax = B->XMax;
    
    				SB[fj].YMin = B->YAve;
    				SB[fj].YMax = B->YMax;
    
    				SB[fj].ZMin = B->ZMin;
    				SB[fj].ZMax = B->ZAve;
    			break;
    
    			case 2: //Box 3
    				SB[fj].XMin = B->XAve;
    				SB[fj].XMax = B->XMax;
    
    				SB[fj].YMin = B->YMin;
    				SB[fj].YMax = B->YAve;
    
    				SB[fj].ZMin = B->ZAve;
    				SB[fj].ZMax = B->ZMax;
    			break;
    
    			case 3: //Box 4
    				SB[fj].XMin = B->XAve;
    				SB[fj].XMax = B->XMax;
    
    				SB[fj].YMin = B->YMin;
    				SB[fj].YMax = B->YAve;
    
    				SB[fj].ZMin = B->ZMin;
    				SB[fj].ZMax = B->ZAve;
    			break;
    
    			case 4: //Box 5
    				SB[fj].XMin = B->XMin;
    				SB[fj].XMax = B->XAve;
    
    				SB[fj].YMin = B->YAve;
    				SB[fj].YMax = B->YMax;
    
    				SB[fj].ZMin = B->ZAve;
    				SB[fj].ZMax = B->ZMax;
    			break;
    
    			case 5: //Box 6
    				SB[fj].XMin = B->XMin;
    				SB[fj].XMax = B->XAve;
    
    				SB[fj].YMin = B->YAve;
    				SB[fj].YMax = B->YMax;
    
    				SB[fj].ZMin = B->ZMin;
    				SB[fj].ZMax = B->ZAve;
    			break;
    
    			case 6: //Box 7
    				SB[fj].XMin = B->XMin;
    				SB[fj].XMax = B->XAve;
    
    				SB[fj].YMin = B->YMin;
    				SB[fj].YMax = B->YAve;
    
    				SB[fj].ZMin = B->ZAve;
    				SB[fj].ZMax = B->ZMax;
    			break;
    
    			case 7: //Box 8
    				SB[fj].XMin = B->XMin;
    				SB[fj].XMax = B->XAve;
    
    				SB[fj].YMin = B->YMin;
    				SB[fj].YMax = B->YAve;
    
    				SB[fj].ZMin = B->ZMin;
    				SB[fj].ZMax = B->ZAve;
    			break;
    
    			default: //Box 1
    				printf("ERROR in Subroutine Subdivide\n");
    
    				return 1;
    			break;
    		}
    	}
    
    	B->SBox=SB;
    	free(fNodeThread);
    	free(fnNodes);
    	nSubDivisions++;
    
    	return 0;
    }
    

    Die Zeile 26 im Code, welche mit dem Kommentar //Problem markiert ist, zeigt die Zeile, welches das Programm bei wiederholtem Aufrufen der Routine zum einfrieren bringt. Die Bildschirmausgabe ist nämlich:
    1.
    2.
    1.
    ##Computer fiert ein#

    Wie kann das sein?

    P.s.: Die CPU leistung geht vor dem Absturz auf 0%. Das Programm kann nicht einfach geschlossen werden - ich schieße es immer ab. Ist also wohl keine Endlosschleife oder so...



  • SeppJ schrieb:

    [code="c"]
    P.P.S.: Da fällt mir noch ein Fehler auf. Wenn SBox ein Zeiger auf dein struct ist (wenn du es also so machst, wie du wolltest und wie ich es dir gezeigt habe), dann ist SBox[fj] vom Typ deines structs. Das heißt, das kannst du nicht dereferenzieren. Es muss also insgesamt B->SBox[fj].XMin heißen.
    P.P.P.S.: Immer noch TCC? Nichts gegen TCC, der ist gut für das, wofür er gemacht ist. Aber dir wurde doch schon erklärt, dass du ihn für etwas nutzt, für dass der Einsatz sogar kontraproduktiv ist. Und während der Entwicklung hätte dir ein "großer" Compiler wie GCC/CLANG/MSVC auch eine deutlich aussagekräftigere Fehlermeldung gegeben. Diese Aussagen gelten auch für LCC. TCC und LCC sind Compiler zum Einsatz auf extrem limitierter Hardware. Sie sind nicht zum Übersetzen von Programmen für limitierte Hardware und sie sind erst recht nicht zum Übersetzen von Programmen auf normaler Hardware für normale Hardware gedacht. Das "ressourcenschonend" in der Beschreibung dieser Compiler bezieht sich nämlich nicht auf die erzeugten Programme, sondern auf den Compiler selbst.

    Hallo Sepp,

    das liegt daran, dass ich verteilt arbeite. Ich habe eine Workstation, auf der ich den fertigen Codeschnippsel (es handelt sich dabei nur um Teilpakete) in mein Hauptprogramm einbauen und mit Visual Studio 2013 kompiliere inkl. Codeoptimierung.

    Aber die Teilprogramme entwickle ich oft unterwegs auf meinem Samsung NC10, welches kurz nach dem zweiten Weltkrieg auf den Markt kam. Da läuft Windows XP und wenn ich mir ein Video von YouTube ansehe, dann ist der eine AtomCPU schon ausgelastet - Hochfahrdauer, bis der AntiVirus läuft 3 min. Da macht VS keinen Spaß 🙂 Aber ich hänge an dem Ding und wenn man im Zug unterwegs ist, oder einfach mal weggeht einfach von der Größe genau mein Ding.
    Das Kompilieren hab ich jetzt auf ShortKeys von meinem NodePad Portable.

    Wenn die Routine läuft, wird sie eingebaut und auch parallelisiert.


  • Mod

    CJens schrieb:

    Die Zeile 26 im Code, welche mit dem Kommentar //Problem markiert ist, zeigt die Zeile, welches das Programm bei wiederholtem Aufrufen der Routine zum einfrieren bringt. Die Bildschirmausgabe ist nämlich:
    1.
    2.
    1.
    ##Computer fiert ein#

    Wie kann das sein?

    Das kann viele Gründe haben. Da du nicht flusht, kann der Fehler auch an ganz anderer Stelle auftreten. Und selbst wenn du flushen würdest, könnte ein Compiler den Code umordnen. Für diese Art Fehler bietet sich ein Debugger zur Analyse an, der findet das Problem sicherlich sehr schnell mit wenig eigener Denkarbeit. Oder Programme wie valgrind, die finden solche Probleme sogar vollautomatisch.

    Sachen, die zu Fehlern einladen:
    -Sinnlose Casts, die den Compiler dazu bringen, bei eventuellen Problemen das Maul zu halten. Wenn ich das recht sehe, braucht du keinen einzigen der Casts.
    -Drei-Sterne-Code. Wortwörtlich. Wieso ist fNodeThread kein *TNode[8][8] ? Warum ist fnNodes kein unsigned long[8] ? Und so weiter...
    -Komplizierter Code, oft wiederholt mit kleinen Änderungen, aber unlesbar geschrieben. Könntest du wirklich einen Fehler in 32-50 oder in 68-153 erkennen, wenn da einer wäre?
    -Was sollen eigentlich die ganzen kryptischen Abkürzungen bei den Variablen- und Typnamen? Sieht irgendwie aus wie ein fehlgeschlagener Versuch mit ungarischer Notation.
    -Wenn Sachen wie x, y, z zusammen gehören, wäre es vielleicht auch eine Idee, sie zusammen zu packen, beispielsweise in ein Array. Das verhindert Schreibfehler und oft kann man den Code vereinfachen.
    -Du versteckst oft Nebeneffekte wie ein Postinkrement in Ausdrücken. Bist du sicher, dass du die alle haben möchtest?
    -Du hast anscheinend globale Variablen (oder dein Code ist zu stark gekürzt). Pfui!

    Der Fehler muss nicht an diesen Dingen liegen, aber dies sind Dinge, die Fehler provozieren. Und zwar genau solche Fehler, wie du sie beobachtest. Selbst wenn es nicht da dran liegt, solltest du dies sowohl korrigieren, als auch lernen, dies nicht mehr so zu tun.

    Wirklich beantworten, was der Fehler ist, können wir nur mit einem vollständigem Minimal(!)beispiel. Falls obige Korrekturen nicht zur Fehlerfindung führen und du beim Erstellen des Minimalbeispiels den Fehler nicht selber findest (der Hauptnutzen eines solchen Beispiels ist, dass man dabei oft den Fehler selber findet! Aber das funktioniert nur, wenn man es ernst nimmt mit dem Kürzen des Codes), dann kannst du noch einmal fragen.

    das liegt daran, dass ich verteilt arbeite. Ich habe eine Workstation, auf der ich den fertigen Codeschnippsel (es handelt sich dabei nur um Teilpakete) in mein Hauptprogramm einbauen und mit Visual Studio 2013 kompiliere inkl. Codeoptimierung.

    Aber die Teilprogramme entwickle ich oft unterwegs auf meinem Samsung NC10, welches kurz nach dem zweiten Weltkrieg auf den Markt kam.

    Ok, das ist ein guter Grund. Bei letzten Mal hattest du ja noch die Theorie, dass der erzeugte Code schneller wäre.



  • **Ich denke mal so:
    **
    --> keine Katze beißt sich selbst in den Schwanz!
    --> wir sind hier im Unterforum C - da sollte es um Fragen der Programmierung mit C gehen!
    --> du fragst aber nach einem Algorithmus und der hat nichts direkt mit C zu tun!

    :p



  • berniebutt schrieb:

    **Ich denke mal so:
    **
    --> keine Katze beißt sich selbst in den Schwanz!
    --> wir sind hier im Unterforum C - da sollte es um Fragen der Programmierung mit C gehen!
    --> du fragst aber nach einem Algorithmus und der hat nichts direkt mit C zu tun!

    :p

    Ähm, nein tu ich nicht.

    Der Algorithmus ist mir klar. Klar ist mir nur nicht, weshalb der Code in Zeile 26 beim Allocieren von Speicher sich aufhängt.

    Aber ich werde das jetzt erstmal durch den VC2012 Debugger jagen, da Sepp meinte, dass der evtl. mehr Hinweise gibt.



  • Hab das Programm jetzt mal mit VC++ 2012 kompiliert. Der Debugger springt auch gleich an.

    Critical error detected c0000374

    Googelt man das kommt heraus, dass es sich um einen Heap Corruption Error handelt.

    Aber steckt mal noch nicht zu viel Gehirnschmalz rein, man findet sehr viel zu dem Thema und ich werde mich erstmal einlesen... wenn das Kind schläft, die Frau im Bett ist etc. und pi pa po 🙂


  • Mod

    Heap Corruption Error: Wahrscheinlichste Ursache ist, du schreibst über die Grenzen eines mit malloc (oder Verwandten) erzeugten Speicherbereichs. Das kann auch heißen, dass du vor diesen Bereich schreibst.



  • Danke Sepp,

    Du hattest mit allem recht:
    1. Debugger hat geholfen, denn VC2012 ist wo anders, dort wo der Fehler lag, ausgestiegen
    2. Ich habe bei über den Speicher hinaus geschrieben bzw. den Speicher zu gering allociert
    3. Der Fehler lag total wo anders.

    Wir können den Thread vorerst schließen (hoffentlich für immer).

    Vielen Dank Euch allen.


Anmelden zum Antworten