WCM Forum

WCM Forum (http://www.wcm.at/forum/index.php)
-   Programmierung (http://www.wcm.at/forum/forumdisplay.php?f=17)
-   -   [C] Funktion returned obwohl void! (http://www.wcm.at/forum/showthread.php?t=174759)

Etienne 25.09.2005 18:54

[C] Funktion returned obwohl void!
 
void *nget(struct names *names, const char *name)
{
while (names)
{
if (strcmp(name,names->name) == 0)
return names->value;
else
names = names->next;
}
return 0;
}

Wie ist das möglich???
Habe diesen Code ausschnitt von airstrike, Datei: names.c
lg Etienne

pong 25.09.2005 20:00

Wäre halt noch ganz brauchbar den Rest des - relevanten - Codes zu sehen und den verwendeten Compiler zu wissen

pong

Etienne 25.09.2005 20:53

da es ein unter Linux laufendes Programm ist, verwendet es den g++ compiler.

#include <string.h>
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "names.h"

/*Funktionsnamespace zum Ordnen von Strings, bzw chars!

*Struktur für Namen, enthält, den Namen, eine Zahl, und ein Pointer
*nächsten namen!
*/
struct names
{
char *name;
void *value;
struct names *next;
};

//Number Get, liefert einen Zeigen auf die Struktur zurück (über esten Parameter),
void *nget(struct names *names, const char *name)
{
while (names)
{ //Array mit names Strukturen durch gehen,
//wenn names ungleich names
if (strcmp(name,names->name) == 0)
//Wenn
return names->value;
else
names = names->next;
}
/* For the moment we fail here to catch bugs */
/*fprintf(stderr,"nget(): Did not find '%s'\n",name);*/
return 0;
}

int nhas(struct names *names, const char *name)
{
while (names)
{
if (strcmp(name,names->name) == 0)
return 1;
else
names = names->next;
}
return 0;
}

void ndef(struct names **names, const char *name, void *value)
{
struct names *n = malloc(sizeof(*n));
n->next = *names;
n->value = value;
n->name = malloc(strlen(name) + 1);
strcpy(n->name,name);
*names = n;
}

void nundef(struct names **names, const char *name)
{
struct names *n;
while (*names)
{
if (strcmp(name,(*names)->name) == 0)
{
n = *names;
*names = (*names)->next;
free(n->name);
free(n);
return;
}
else
{
names = &((*names)->next);
}
}
}

void nmap(struct names *names, void (*fn)(const char *name, void *value))
{
while (names)
{
fn(names->name,names->value);
names = names->next;
}
}

void nfree(struct names **names)
{
struct names *n;
while (*names)
{
n = *names;
*names = (*names)->next;
free(n->name);
free(n);
}
}

void nwrite_str(struct names *names, FILE *target)
{
while (names)
{
fprintf(target,"\"%s\" \"%s\"\n",names->name,(char *)names->value);
names = names->next;
}
}

static void skip_ws(FILE *f)
{
int c;
while (isspace(c = fgetc(f)) && (c != EOF)) {}
ungetc(c,f);
}

/*
* Skips #..., whitespace and respects double quotes
* Returns NULL at EOF or error
*/
static char *next_token(FILE *f)
{
int c;
static char token[256];
char *s;

again:
skip_ws(f);
c = fgetc(f);
ungetc(c,f);
if (c == '"')
{
if (fscanf(f,"\"%[^\"\n]\"",token) != 1)
return 0;
}
else if (c == '#')
{
if (fscanf(f,"%*[^\n]") != 0)
return 0;
goto again;
}
else
{
if (fscanf(f,"%[^# \n\t={}]",token) != 1)
return 0;
}
s = malloc(strlen(token) + 1);
strcpy(s,token);
return s;
}

void nread_str(struct names **names, FILE *target)
{
char *name,*value;
while ((name = next_token(target)))
{
value = next_token(target);
if (!value)
{
fprintf(stderr,"nread(): Invalid input at end of file.\n");
return;
}
ndef(names,name,value);
free(name);
}
}

lg Etienne

Biri 25.09.2005 21:22

hi,

was ist daran ungewöhnlich?
die funktion ist so deklariert, dass sie einen void pointer zurückliefern kann und genau das macht sie.

beachte: void pointer != void

es wird hier also einfach ein untypisierter zeiger retour gegeben - etwas "gefährlich", außer man weiß, was man macht.

der fall "return 0" ist - zugegebenerweise etwas ungewöhnlich, aber durchaus möglich - es wird eine referenz auf die speicherstelle an adresse 0 retour geliefert.
und genau hier wirds problematisch - der aufrufende der funktion erhält zugriff auf den speicher an stelle 0 und kann dort irgendwas reinschreiben - und das führt dann wohl früher oder später zum programmabsturz - einer sog. "memory access violation"

eine typsichere programmiersprache wie z.B. C# würde soetwas nicht erlauben und bereits beim kompilieren einen fehler melden.

fg
-hannes

Who-T 26.09.2005 09:42

Zitat:

Original geschrieben von Biri

der fall "return 0" ist - zugegebenerweise etwas ungewöhnlich, aber durchaus möglich - es wird eine referenz auf die speicherstelle an adresse 0 retour geliefert.

Code:

$> grep NULL /usr/include/linux/stddef.h
#undef NULL
#define NULL 0
#define NULL ((void *)0)

Es ist nicht ungewoehnlich NULL zurueckzugeben. dies ist bei den meisten bibliotheken der standard. NULL ist (wie der name schon sagt) definiert auf 0.

Code:

return NULL;
ist also das gleiche wie
Code:

return 0;
wobei ich persoenlich erstes bevorzuge.


edit:
ad typsichere sprachen. die speicheradresse 0 ist vom typ her eine gueltige adresse. der compiler schreit deswegen nicht.

Biri 26.09.2005 10:00

hi,

stimmt, es ist nicht ungewöhnlich NULL zurückzugeben - man schreibt dann für gewöhnlich aber auch NULL hin, nicht 0.
Die tatsache, dass 0 durch NULL ersetzt wird (durch das define) erklärt eigentlich eh schon alles.

ad typsichere sprachen:

C#:
unsafe void* fu1()
{
return 0;
}

Compilererror:
error CS0266: Cannot implicitly convert type 'int' to 'void*'. An explicit conversion exists (are you missing a cast?)


hingegen:
unsafe void* fu1()
{
return null;
}

========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

fg
-hannes

Etienne 27.09.2005 16:11

danke wieder was gelernt!

lg Etienne


Alle Zeitangaben in WEZ +2. Es ist jetzt 15:38 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
© 2009 FSL Verlag