Datentyp für Zeigerarithmetik



  • @manni66 sagte in Datentyp für Zeigerarithmetik:

    Das Ergebnis sollte identisch sein. Die Warnung an dieser Stelle finde ich fragwürdig.

    Ja ich dachte auch immer, dass diese Zugriffsweisen beliebig getauscht werden können; deshalb frage ich ja.

    Das sind die ganz normalen Standardeinstellungen von Visual Studio. Wenn ich den Warnlevel verringere, bleibt die Warnung natürlich weg, aber das ist ja auch nicht gut, oder? Theoretisch könnte es ja sein, dass die Grenze bzw. der Wert von i irgendwann einmal größer ist.🙄

    @SeppJ sagte in Datentyp für Zeigerarithmetik:

    Prinzipiell richtig. Aber wenn man einen int deklariert und bei der einzigen Nutzung diesen in size_t castet, dann hat man wahrscheinlich den falschen Typen gewählt. Warum hörst du nicht auf Th69?

    Weil die OpenGL-Funktion "glDrawElements" eben gerne int bzw. unsigned int haben möchte und dann wieder woanders eine Warnung auftaucht.🤔

    Es bestehen die gleichen Gefahren, vor denen hier so übertrieben gewarnt wird. Bei Warnungen ist es Abwägungssache, was der Programmierer wohl gemeint hat und ob das wirklich zu dem Code passt. Der Code ist ja nicht direkt falsch. Warnungen gibt es deshalb bei üblichen Fehlermustern, wo prinzipiell korrekter Code nicht das macht, was die meisten Leute denken. Überlaufende Arrayindizes können ja in irgendwelchen verschwurbelten Szenarien noch Sinn machen. Aber das Szenario (großer Typ) + (potentiell überlaufende Rechnung mit kleinen Typen) kommt auch ganz losgelöst von Pointertypen eher vor und ist wohl nie das was wirklich gemeint ist.

    Eigentlich habe ich mich ja nur an das gehalten, was der Compiler verlangt hat und vor der Multiplikation in einen breiteren Datentypen umgewandelt.



  • @Peter-Viehweger sagte in Datentyp für Zeigerarithmetik:

    Weil die OpenGL-Funktion "glDrawElements" eben gerne int bzw. unsigned int haben möchte und dann wieder woanders eine Warnung auftaucht.

    Erm, bitte was? Du sollst für deine lokalen Schleifenvariablen size_t benutzen, die tauchen nur noch im Schleifenrumpf auf. Würde mich sehr wundern, wenn es dadurch Warnungen geben sollte. Pauschal nur int32/uint32 zu benutzen, weil es irgendwo mit OpenGL Probleme geben könnte halte ich für fragwürdig. Benutze die richtigen Datentypen im richtigen Kontext! Dafür zahle ich auch gern 1€ Euro in´s Phrasenschwein.



  • Also das hier ist jetzt mal mehr oder weniger der "Originalcode" zur Berechnung der Unterseite eines Würfels (d.h. eigentlich ist das Ganze 6 Mal so lang, mir ist da noch nichts Besseres eingefallen):

    #include <stdlib.h>
    
    float *vertices;
    unsigned int numvertices;
    unsigned int *indices;
    unsigned int numindices;
    
    int main()
    {
    	size_t i;
    	size_t j;
    
    	float *verticesptr;
    	unsigned int *indicesptr;
    	unsigned int indicesoffset;
    
    	unsigned int xelements = 12;
    	unsigned int yelements = 12;
    	unsigned int zelements = 12;
    
    
    	numvertices = 2 * (xelements + 1) * (yelements + 1) * 6 + 2 * (xelements + 1) * (zelements + 1) * 6 + 2 * (yelements + 1) * (zelements + 1);
    	vertices = malloc(numvertices * sizeof(*vertices));
    	if(vertices == NULL)
    	{
    		return 1;
    	}
    
    	numindices = 2 * xelements * (yelements + 1) * 3 + 2 * (xelements + 1) * yelements * 3 + 2 * xelements * (zelements + 1) * 3 + 2 * (yelements + 1) * zelements * 3 + 2 * yelements * (zelements + 1) * 3;
    	indices = malloc(numindices * sizeof(*indices));
    	if(indices == NULL)
    	{
    		return 2;
    	}
    
    	//vertices for bottom side
    	verticesptr = vertices;
    
    	for(i = 0; i < (yelements + 1); i++)
    	{
    		for(j = 0; j < (xelements + 1); j++)
    		{
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 0) = (float) j / (float) xelements;
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 1) = (float) i / (float) yelements;
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 2) = 0.0f;
    		}
    	}
    
    	//indices for horizontal lines on bottom side
    	indicesptr = indices;
    	indicesoffset = 0;
    
    	for(i = 0; i < (yelements + 1); i++)
    	{
    		for(j = 0; j < xelements; j++)
    		{
    			*(indicesptr + i * xelements * 3 + j * 3 + 0) = indicesoffset + i * (xelements + 1) + j;
    			*(indicesptr + i * xelements * 3 + j * 3 + 1) = indicesoffset + i * (xelements + 1) + j + 1;
    			*(indicesptr + i * xelements * 3 + j * 3 + 2) = indicesoffset + i * (xelements + 1) + j + 1;
    		}
    	}
    
    	//indices for vertical lines on bottom side
    	indicesptr = indicesptr + yelements * (xelements + 1) * 3;
    	indicesoffset = indicesoffset + (yelements + 1) * xelements;
    
    	for(i = 0; i < yelements; i++)
    	{
    		for(j = 0; j < (xelements + 1); j++)
    		{
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 0) = indicesoffset + i * (xelements + 1) + j;
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 1) = indicesoffset + (i + 1) * (xelements + 1) + j;
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 2) = indicesoffset + (i + 1) * (xelements + 1) + j;
    		}
    	}
    
    	return 0;
    }
    

    Die globalen Variablen ganz oben sind übrigens nur im Codebeispiel vorhanden und werden eigentlich als Parameter an die Funktion übergeben.

    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    

    Also auch nicht besser......



  • Ne, wie auch? Du benutzt ja immer noch uint64 und unsigned int bei der Multiplikation (Zeilen 43-45, 57-59 und 71-73). Sorg´ dafür, dass alle Operatoren vom Typ uint64 oder size_t sind, dann verschwinden auch die Warnungen.



  • #include <stdlib.h>
    
    float *vertices;			//
    size_t numvertices;	//Eigentlich gibt es eine Funktion, die diesen Code ausführt und
    unsigned int *indices;		//Zeiger auf diese Variablen als Parameter übernimmt
    size_t numindices;	//
    
    int main()
    {
    	size_t i;
    	size_t j;
    
    	float *verticesptr;
    	unsigned int *indicesptr;
    	size_t indicesoffset;
    
    	size_t xelements = 12;
    	size_t yelements = 12;
    	size_t zelements = 12;
    
    
    	numvertices = 2 * (xelements + 1) * (yelements + 1) * 6 + 2 * (xelements + 1) * (zelements + 1) * 6 + 2 * (yelements + 1) * (zelements + 1);
    	vertices = malloc(numvertices * sizeof(*vertices));
    	if(vertices == NULL)
    	{
    		return 1;
    	}
    
    	numindices = 2 * xelements * (yelements + 1) * 3 + 2 * (xelements + 1) * yelements * 3 + 2 * xelements * (zelements + 1) * 3 + 2 * (yelements + 1) * zelements * 3 + 2 * yelements * (zelements + 1) * 3;
    	indices = malloc(numindices * sizeof(*indices));
    	if(indices == NULL)
    	{
    		return 2;
    	}
    
    	//vertices for bottom side
    	verticesptr = vertices;
    
    	for(i = 0; i < (yelements + 1); i++)
    	{
    		for(j = 0; j < (xelements + 1); j++)
    		{
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 0) = (float) j / (float) xelements;
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 1) = (float) i / (float) yelements;
    			*(verticesptr + i * (xelements + 1) * 6 + j * 6 + 2) = 0.0f;
    		}
    	}
    
    	//indices for horizontal lines on bottom side
    	indicesptr = indices;
    	indicesoffset = 0;
    
    	for(i = 0; i < (yelements + 1); i++)
    	{
    		for(j = 0; j < xelements; j++)
    		{
    			*(indicesptr + i * xelements * 3 + j * 3 + 0) = indicesoffset + i * (xelements + 1) + j;
    			*(indicesptr + i * xelements * 3 + j * 3 + 1) = indicesoffset + i * (xelements + 1) + j + 1;
    			*(indicesptr + i * xelements * 3 + j * 3 + 2) = indicesoffset + i * (xelements + 1) + j + 1;
    		}
    	}
    
    	//indices for vertical lines on bottom side
    	indicesptr = indicesptr + yelements * (xelements + 1) * 3;
    	indicesoffset = indicesoffset + (yelements + 1) * xelements;
    
    	for(i = 0; i < yelements; i++)
    	{
    		for(j = 0; j < (xelements + 1); j++)
    		{
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 0) = indicesoffset + i * (xelements + 1) + j;
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 1) = indicesoffset + (i + 1) * (xelements + 1) + j;
    			*(indicesptr + i * (xelements + 1) * 3 + j * 3 + 2) = indicesoffset + (i + 1) * (xelements + 1) + j;
    		}
    	}
    
    	return 0;
    }
    
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    1>warning C4267: "=": Konvertierung von "size_t" nach "unsigned int", Datenverlust möglich
    

    Für "indices" ist "unsigned int" als Datentyp fest vorgegeben: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawElements.xhtml

    type

    Specifies the type of the values in indices. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.



  • Wenn du keine der beiden Warnings haben willst (gut), und auch keine der beiden Warnings deaktivieren/unterdrücken (vermutlich auch gut), dann bleibt dir nur übrig irgendwo zu casten.

    Also entweder mit 32 Bit Schleifenzähler: vor der Multiplikation 32 -> 64 Bit casten. Oder mit 64 Bit Schleifenzähler: vor der Zuweisung 64 -> 32 Bit casten.



  • @Peter-Viehweger
    Eine kleine Frage. Kompilierst du das Programm unter 64Bit?

    Wenn ich nämlich dein Programm unter 64Bit kompiliere, komme ich auf die gleichen Warnungen. Unter 32 Bit nicht.

    Im folgenden Beispiel ist i vom Typ size_t und die 12 vom Typ int.

    *(data + i * 12 + j) = 1.0f;
    

    Also habe ich Testweise den Typ von size_t auf unsigned int umgestellt und das Integer Literal u benutzt. Dadurch nutzen alle Elemente der Rechnung den gleichen Datentyp.

    Probiere doch mal ob der folgende Code nun läuft.

    #include <stdlib.h>
    
    float* vertices;			//
    unsigned int numvertices;	//Eigentlich gibt es eine Funktion, die diesen Code ausführt und
    unsigned int* indices;		//Zeiger auf diese Variablen als Parameter übernimmt
    unsigned numindices;	//
    
    int main()
    {
    	unsigned int i;
    	unsigned int j;
    		
    	float* verticesptr;
    	unsigned int* indicesptr;
    	unsigned int indicesoffset;
    
    	unsigned int xelements = 12;
    	unsigned int yelements = 12;
    	unsigned int zelements = 12;
    
    
    	numvertices = 2u * (xelements + 1u) * (yelements + 1u) * 6u + 2u * (xelements + 1u) * (zelements + 1u) * 6u + 2u * (yelements + 1u) * (zelements + 1u);
    	vertices = malloc(numvertices * sizeof(*vertices));
    	if (vertices == NULL)
    	{
    		return 1;
    	}
    
    	numindices = 2u * xelements * (yelements + 1u) * 3u + 2u * (xelements + 1u) * yelements * 3u + 2u * xelements * (zelements + 1u) * 3u + 2u * (yelements + 1u) * zelements * 3u + 2u * yelements * (zelements + 1u) * 3u;
    	indices = malloc(numindices * sizeof(*indices));
    	if (indices == NULL)
    	{
    		return 2;
    	}
    
    	//vertices for bottom side
    	verticesptr = vertices;
    
    	for (i = 0; i < (yelements + 1u); i++)
    	{
    		for (j = 0; j < (xelements + 1u); j++)
    		{
    			*(verticesptr + i * (xelements + 1u) * 6u + j * 6u + 0u) = (float)j / (float)xelements;
    			*(verticesptr + i * (xelements + 1u) * 6u + j * 6u + 1u) = (float)i / (float)yelements;
    			*(verticesptr + i * (xelements + 1u) * 6u + j * 6u + 2u) = 0.0f;
    		}
    	}
    
    	//indices for horizontal lines on bottom side
    	indicesptr = indices;
    	indicesoffset = 0;
    
    	for (i = 0; i < (yelements + 1u); i++)
    	{
    		for (j = 0; j < xelements; j++)
    		{
    			*(indicesptr + i * xelements * 3u + j * 3u + 0u) = indicesoffset + i * (xelements + 1u) + j;
    			*(indicesptr + i * xelements * 3u + j * 3u + 1u) = indicesoffset + i * (xelements + 1u) + j + 1u;
    			*(indicesptr + i * xelements * 3u + j * 3u + 2u) = indicesoffset + i * (xelements + 1u) + j + 1u;
    		}
    	}
    
    	//indices for vertical lines on bottom side
    	indicesptr = indicesptr + yelements * (xelements + 1u) * 3u;
    	indicesoffset = indicesoffset + (yelements + 1u) * xelements;
    
    	for (i = 0; i < yelements; i++)
    	{
    		for (j = 0; j < (xelements + 1u); j++)
    		{
    			*(indicesptr + i * (xelements + 1u) * 3u + j * 3u + 0u) = indicesoffset + i * (xelements + 1u) + j;
    			*(indicesptr + i * (xelements + 1u) * 3u + j * 3u + 1u) = indicesoffset + (i + 1u) * (xelements + 1u) + j;
    			*(indicesptr + i * (xelements + 1u) * 3u + j * 3u + 2u) = indicesoffset + (i + 1u) * (xelements + 1u) + j;
    		}
    	}
    
    	return 0;
    }
    

  • Mod

    @Quiche-Lorraine: Deine "Lösung" geht am Problem vorbei



  • @Quiche-Lorraine sagte in Datentyp für Zeigerarithmetik:

    Dadurch nutzen alle Elemente der Rechnung den gleichen Datentyp.

    Eben nicht. z.B.
    (indicesptr + i * (xelements + 1u) * 3u + j * 3u + 1u)
    Wenn rechts alles unsigned int ist, dann bleibt da immer noch ptr + unsigned int. Und diesen Operator gibt es nicht - es gibt bloss ptr + ptrdiff_t. Also Konvertierung unsigned_int -> ptrdiff_t. Also 32 -> 64 Bit auf einem 64 Bit System.
    Und daher dann die Warning dass man erst mit 32 Bit rumrechnet und danach erst auf 64 Bit erweitert. Was zur Folge hat dass man Überläufe bekommen kann, die man hätte vermeiden können wenn man erst auf 64 Bit castet bevor man rechnet.



  • @hustbaer
    Danke für die Info, das habe ich übersehen


Log in to reply