IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Patrik Pastor:10.9.2019 20:29
char* fmt;
va_start(ap, fmt);

jak to, ze je druhy argument typ pointer?(adresa). V dokumentaci je druhy argumeny typu posledniho znameho typu (ale typ "adresa", je prece v jakemkoliv bytu). Rad bych chtel pochopit, jak funguje druhy argument "fmt" (typu char* - adresa na jeden byte) v teto funkci. Dik za odpoved

 
Odpovědět
10.9.2019 20:29
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Patrik Pastor
DarkCoder:11.9.2019 9:02

Je třeba uvést, že kód má souvislost s vlastní implementací funkce printf(). Jinak kód nikomu nic neřekne. Jinak va_start není funkce ale makro. Ukazatel na char (char *) nemusí nutně znamenat ukazatel na znak. V drtivé většině případů a je to i tento případ, se jedná o ukazatel na řetězec. Prvním argumentem vlastní funkce printf() je konstantní ukazatel na řetězec. Je to zároveň i poslední známý fixní parametr. Proto pro párování s va_list je použit ukazatel.

Nahoru Odpovědět
11.9.2019 9:02
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Patrik Pastor:11.9.2019 9:22

Proto pro parovani je s va_list je pouzit ukazatel.

Pochopil bych ukazatel pouzit kvuli adresy zacatku pole (string), ale ne jako hodnotu argumentu fukce (jakou hodnotu ma pointer? - pokud neni dereferencovan - coz ve vyse zmineme prikladu neni - ma hodnotu adresy), takze jak muze byt 'TYPE' pouzit jako adresa?

dokumentace:

The argument last is the name of the last argument before the variable ar‐
gument list, that is, the last argument of which the calling function knows
the type.

Type adresy (jak je to ve funkci pouzito)? To se mi nejak nezda

Editováno 11.9.2019 9:23
 
Nahoru Odpovědět
11.9.2019 9:22
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Patrik Pastor
DarkCoder:11.9.2019 10:03

V C se pole nebo řetězec nepředává jako celek, ale předává se ukazatel na začátek pole. Pokud chci funkci předat pole, musí být argument deklarován jako ukazatel.

char p[] = "Test", *pp = p;
char *p2 = "Test2";

p, pp, p2 - vše jsou ukazatele na začátek pole (na první znak řetězce).

void vypis(char *pole);

// Volání funkce

vypis(p);
vypis(pp);
Nahoru Odpovědět
11.9.2019 10:03
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Patrik Pastor:11.9.2019 10:10

toto ale opet neni odpoved na muj dotaz, to ze se pole predava snad vim, jak sem zacal delat v c. Ale ja se ptam, jak to, ze ve funkci va_start(va_list ap, type), je jako hodnota type pouzit pointer bez dereference? Nehlede na to ze ukazuje na zacatek pole. Ale v te funkci se bere jako TYPE POSLEDNI ZNAMY TYP - ted sem to psal, je to z dokumentace. JAKY je posledni znamy typ Pointeru (NE HODNOTA - ALE TYP)? Co je typ pointeru? Jeho adresa nebo dereferencovana hodnota? Tak prosim odpovez na tuto otazku, a ne co znamena pointer ve stringu

 
Nahoru Odpovědět
11.9.2019 10:10
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Patrik Pastor
DarkCoder:11.9.2019 10:28

Trochu pokory, pokud požaduješ odpověď. Mnoho programátorů v C netuší, že když se předává pole předává se ukazatel na pole a ne celé pole. To co řešíš je základní syntax ukazatelů.

char *p;

V definici ukazatelova proměnná je p, nikoli *p. Hvězdička v definici značí pouze odlišnost od klasické proměnné. Pokud je ukazatel použít ve funkci, hvězdička se nepoužívá. Pokud chci získat hodnotu na kterou ukazatel ukazuje, dereferencuje se ukazatel a před ukazatel se dává hvězdička.

Jelikož typ prvního parametrů ve funkci s proměnným počtem parametrů je ukazatel na char, musí být druhy argument macra va_start také ukazatel. Jelikož se nejedná o definici, tak v něm žádná hvězdička není.

Nahoru Odpovědět
11.9.2019 10:28
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Patrik Pastor:11.9.2019 10:29

A jeste jedna vec. Pokud bych zmenil tento argument:

va_start(ap, fmt)

na

va_start(ap *fmt)

-- Bude to fungovat stejne.... Takze to je na co se ptam, ve druhem pripade je pointer dereferencovany (takze ted je tam konecne hodnota, kterou funkce vyzaduje - aby mela znamy typ a vedel kdy skoncit), ale v prvnim pripade pointer dereferncovany neni.... JAK JE TO MOZNE? Ze funguji oba? A obzvlast kdyz pointer NENI dereferencovany, takze 'hodnota' kterou funkce va_start dostane je hexadecimalni cislo reprezentujici adresu pointeru (protoze neni dereferencovany).

 
Nahoru Odpovědět
11.9.2019 10:29
Avatar
Odpovídá na DarkCoder
Patrik Pastor:11.9.2019 10:37

otazka teda je, proc je potreba 'odlisovat' promenne mezi sebou - a tedy zavadet v definici '*' - hvezdicku, ale nikoli jako 'dereferenci', pouze na odliseni v definici. Celkem je to matouci a nechapu smysl nebo duvod proc je tato potreba. Kdyz mam v definici funkci pouzite argumenty, kazdy ma svuj nazev a svuj datovy typ. Proc je teda tato konvence 'rozslisovat' (cim?) mezi sebou promenne hvezdickou? To je fakt matouci

Editováno 11.9.2019 10:37
 
Nahoru Odpovědět
11.9.2019 10:37
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Patrik Pastor
DarkCoder:11.9.2019 11:27

Není na tom nic matoucího. Jak jinak by si chtěl oddělit 2 typy proměnné, kde jedná obsahuje adresu a druhá hodnotu? Proto je v C v definici pro ukazatelovou proměnnou použitá hvězdička před jménem a pro běžnou proměnnou pouze jméno.

int i = 0, *pi = NULL;

pi = &i; // zde se * nepouziva
*pi = 100; // nebo
i = 100;
printf("%d %d %p %p\n", i, *pi, &i, pi);

Vypis hodnot a adres dvěma způsoby. Přiřazení adresy proměnné ukazateli a hodnoty proměnné i přímo a pomocí ukazatele.

Nahoru Odpovědět
11.9.2019 11:27
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Patrik Pastor
Martin Dráb:11.9.2019 23:51

A jeste jedna vec. Pokud bych zmenil tento argument:

Makro va_start opravdu nemusí dereferenceovat (přistupovat) na pointer předávaný v druhém argumentu. Jeho úkolem totiž je nastavit první parametr (va_list) tak, aby ukazoval na první z parametrů skrývajících se v "argumentu" .... fmt musí být poslední parametr před ..., protože na zásobníku jsou parametry při volání variadické funkce uloženy následovně:

  • 1. normální parametr,
  • . . .
  • N-1. normální parametr,
  • fmt,
  • první argument v ...
  • . . .
  • poslední argument v ....

(počítáno zleva doprava. Jelikož zásobník roste směrem k nižším adresám, obvykle se parametry předávají v opačném pořadí (zprava doleva), ale chtěl jsem číslovat pořadí tak, jak jej vidíš ve zdrojovém kódu).

Makro va_start ti pak prostě vrátí

(void **)&fmt + 1

Do parametru fmt tedy nepřistupuje (nečte jeho hodnotu). Jde jen o to získat jeho adresu na zásobníku.

Z implementace va_start a jemu podobných je zároveň vidět, jak je to celé potenciálně nebezpečné, protože:

  1. programátor musí vědět, zda-li do variadické funkce předává správný počet parametrů (protože ta funkce to zjistit sama nemůže),
  2. programátor musí specifikovat parametry správného typu (překladač toto nedokáže zkontrolovat, pokud se nejdná o funkce, které zná (např. printf), a tedy ví, jak např. z formátovacího řetězce odhadnout počet variadických parametrů).
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
11.9.2019 23:51
2 + 2 = 5 for extremely large values of 2
Avatar
DarkCoder
Člen
Avatar
DarkCoder:12.9.2019 1:27

Ano, úkolem makra va_start je nastavení pozice na zásobníku. To je důvod, proč se do va_start zadává poslední známý parametr před .... Následné argumenty lze pak snadno přečíst pomocí va_arg. Doplním praktickou ukázku.

void printargs(int n, ...) {
        va_list list;

        va_start(list, n);
        for (; n; n--) printf("%d ", va_arg(list, int));
        va_end(list);
}

s voláním např.

printargs(5, 10, 20, 30, 40, 50);

Přesně tak, celé to nebezpečí spočívá v tom, že překladač skutečně nekontroluje hodnotu odpovídající počtu parametrů, nehlásí varování ani nepozastaví překlad. Je jen na programátorovi jak se k tomu celému postaví. Obvykle však existuje nějaká vazba mezi počtem argumentů které budou následovat a argumenty a takto "natvrdo" se to nezadává popř. výjimečně. Je to spíše jen experimentální ukázka na které je princip činnosti dobře vidět. Dobrý programátor by měl vědět, jak si s tím poradit. Funkce s variabilním počtem parametrů s jedním parametrem představujícím počet variadických parametrů je jedním ze způsobů jak taková funkce vypadá.

Tím druhým způsobem, o poznání frekventovanějším, je tvorba variadické funkce za pomocí formátovacího řetězce, díky kterému lze specifikovat typy parametrů (viz. zmíněná funkce printf() a další). Zde je jen na programátorovi jak správně napáruje specifikace formátu k danému typu.

Existují další způsoby ale tyto dva jsou nejčastější neboť jsou nejznámější.

Nahoru Odpovědět
12.9.2019 1:27
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.