NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
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í.

Diskuze: Nechtěná změna hodnoty délky pole a prvních 4 bytů pole

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Caster
Člen
Avatar
Caster:23.10.2022 15:56

Při volání funkce předávám poslední parametr jako ukazatel na hodnotu délky pole. Z neznámých důvodů se ale po provedení funkce hodnota délky pole změní ze 16 na 20 a první 4 byty pole se přepíší jinými hodnotami.

Zkusil jsem: Na začátku programu definuji:

unsigned char digest16[16];
unsigned int  digest16_len = 16;
unsigned int* ptrdigest16_len = &digest16_len;
unsigned char PMKID[16];
unsigned char PMKID_Salt[20];

do pole PMKID pak uložím 16 bytů převedených z:

const char PMKID_str[] = "b0b606458a7945cf7c80b7fefe390506";

Chci docílit: Aby se po volání funkce nezměnila hodnota délky pole digest16_len a nepřepsaly se mi první 4 byty pole PMKID.

Tuším, že je problém asi v nesprávné definice ukazatelu na délku pole PMKID.

Vlastní volání funkcer vypadá takto, funkce vrátí správný výsledek do pole digest16:

HMAC(EVP_sha1(), (const char*)digest, 32, (const unsigned char*)PMKID_Salt, sizeof(PMKID_Salt), digest16, ptrdigest16_len);
 
Odpovědět
23.10.2022 15:56
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:23.10.2022 18:36

Nečteš dokumentaci. Je naprosto v pořádku že se hodnota proměnné přidané jako argument mění, neboť funkce vrací ukazatel na tuto proměnnou. Poslední parametr je totiž výstupní nikoli vstupní.

Jinak je zbytečné ukládat si velikost pole jehož rozměr znáš. Používej operátor preprocesoru sizeof.

Dále jsem si všiml že dost často nevytváříš vazby mezi velikostí pole a polem. Takovýto postup brzy povede k chybě v programu.

Nahoru Odpovědět
23.10.2022 18:36
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:23.10.2022 18:49

Stále mi nejsou moc jasné rozdíly v definici polí. Nicméně jsem problém vyřešil zadáním posledních dvou parametrů NULL, NULL (inspirovalo mě pár odkazů na použití funkce na Internetu) a přiřazení výsledku funkce do pole:

unsigned char* digest16 = NULL;
digest16 = HMAC(EVP_sha1(), (const char*)digest, 32, (const unsigned char*)PMKID_Salt, sizeof(PMKID_Salt), NULL, NULL);
 
Nahoru Odpovědět
23.10.2022 18:49
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:23.10.2022 19:15

Co konkrétně Ti na polích není jasné?

Nahoru Odpovědět
23.10.2022 19:15
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:23.10.2022 20:50

Přiřazování hodnot, například:

unsigned char digest[32];
const char MAC_AP[] = "c0c1c04bfc68";
char* password = { (char*)("MTRTogrt") };
 
Nahoru Odpovědět
23.10.2022 20:50
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:23.10.2022 21:28

Takže inicializace řetězců. Nic na tom není.

První případ je pole pro uložení 32 znaků nebo řetězce o délce 31 znaků (ukončeno nul znakem). Pokud je globální, obsahuje nuly, pokud je statické, obsahuje nuly, pokud je lokální, obsahuje odpad.

Druhý případ je pole obsahující řetězec který nelze měnit, protože const. Délku si umí spočítat překladač, je rovná počtu znaků + 1 nul znak. Funguje to tak že se vytvoří řetězec v rabulce řetězců, vytvoří se pole a zkopíruješ se řetězec do tohoto pole. Lépe je konstantní řetězec vytvořit takto:

char* str ="retezec";

Takovýto zápis je rychlejší neboť se řetězec vytvoří pouze v tabulce řetězců, a ty držíš pouze ukazatel na řetězec. Opět takovýto řetězec nelze měnit.

Pokud chceš měnit řetězec, musíš jej deklarovat jako pole:

#define SIZE 10
char str[SIZE];

Nebo vytvořit dynamicky:

char *str = NULL;

A pak použít malloc() nebo calloc() a nakonec uvolnit pomocí free().

Nelze deklarovat pole takto:

char str[];

Chybí rozměr.

Nahoru Odpovědět
23.10.2022 21:28
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:23.10.2022 21:56

Dále když máš řetězec velké délky tak nechej délku na kompilátoru a nepočítej délku sám. Nikdy!

Když deklaruješ a inicializujes pole pro uložení řetězce takto:

char str[] = "test";

Tak str zabírá v paměti 5 bytů a lze uložit až 4 znaky.

Pokud takto:

char str[10] = "test";

tak str zabírá v paměti 10 bytů a lze uložit až 9 znaků. Ale lze změnit obsah třeba na "testuji" pomocí strcpy() protože se rám nový řetězec vejde. To u prvního případů nelze.

Nahoru Odpovědět
23.10.2022 21:56
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:24.10.2022 7:43

Nepřišel jsem na to jak rovnou převést string na pole:

test = random_string(8);
password = &test[0];

kde je definováno

string test;
char* password = NULL;
 
Nahoru Odpovědět
24.10.2022 7:43
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:24.10.2022 12:07

Je mnoho způsobů..

Máme-li řetězec:

string str = "muj retezec";

Pak pro konstantní řetězce:

const char* arr1 = str.c_str();

nebo

char* arr2 = &str[0];

Pro modifikovatelný řetězec:

char* arr3 = new char[str.length() + 1];
str.copy(arr3, str.length());
arr3[str.length()] = '\0';
Nahoru Odpovědět
24.10.2022 12:07
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:24.10.2022 19:30

Neví, jak to zadat na jednom řádku:

password = &random_string(8)[0];

Hlásí mi chybu:
C26815 Ukazatel je nepropojený, protože ukazuje na dočasnou instanci, která byla zničena

 
Nahoru Odpovědět
24.10.2022 19:30
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:25.10.2022 2:59

Jak chceš udržovat adresu objektu který si ani neuložíš?

Takto:

std::string str = random_string(8);
const char* password = str.c_str();
// const char* password = &str[0];

Nicméně toto není to co potřebuješ, to je určeno pro konstantní řetězce, ty potřebuješ pole modifikovat.

Navíc generování řetězců není správná cesta k dosažení toho čeho chceš dosáhnout. Je třeba postupovat systematicky, obsah pole měnit jasně daným způsobem. Tak jak fungují např. staré tachometry nebo mechanické elektroměry. Dále je třeba optimalizovat na rychlost. To znamená že jakákoli konverze nepřichází v úvahu. Zapomeň. Používej C-čkové řetězce a nepoužívej string z C++ které jsou sice pohodlné ale pomalé. Vytvářej si své vlastní funkce a nekopíruj kde co někdo napsal. Práci s polem budeš dělat prakticky pořád, takže dle toho vytvoř funkce. Zadávej co nejméně dat, vracej co nejméně dat. Neduplikuj. Ač je v 99% logické a správné tvořit funkce s parametry a vracet hodnoty, tak ty se musíš zamyslet a v některých případech to obejít. Podívej se např. na funkci random string(). Vrací řetězec, popř. referenci či ukazatel, má parametr. Takto tu funkci teď psát nebudeš. Funkce musí přebírat data zvenčí. Natahování argumentů a vrácení hodnot stojí procesorový čas, ty jej nemáš nazbyt.

Nakonec Ti doporučím zainvestovat více času do studia problematiky ukazatelů, budeš pak postupovat mnohem snáz a nebude to styl pokus omyl.

Nahoru Odpovědět
25.10.2022 2:59
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:25.10.2022 10:13

O rychlost mi samozřejmě jde. Zkouším upravit program z Internetu, který mi pod Linuxem & GPU běží rychlostí 2 bilióny hashí/s (SHA256) na Windows.

 
Nahoru Odpovědět
25.10.2022 10:13
Avatar
Caster
Člen
Avatar
Caster:26.10.2022 0:16

U funkce:

void hostRandomGen(unsigned long* x) {
    *x ^= (*x << 21);
    *x ^= (*x >> 35);
    *x ^= (*x << 4);
}

Mi překladač hlásí: Upozornění #63-D shift count is too large

Volání funkce:

hostRandomGen(&rngSeed);

¨
Definice:

unsigned long rngSeed = timems();

V čem je problém ?

 
Nahoru Odpovědět
26.10.2022 0:16
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:26.10.2022 10:00

Shiftuješ s příliš vysokou hodnotou.

Pro generování náhodného čísla můžeš použít xorshift32.

uint32_t xorshift32(uint32_t* x) {
        *x ^= *x << 13;
        *x ^= *x >> 17;
        *x ^= *x << 5;
        return *x;
}

kde x je ukazatel na seed, kterému jeho počáteční hodnotu můžeš nastavit např. takto:

time_t t;
uint32_t seed;

time(&t);
seed = (uint32_t)(t);
Nahoru Odpovědět
26.10.2022 10:00
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:26.10.2022 23:04

Díky, nechal jsem původní kód. Zjistil jsem, že je v Linuxu unsigned long 8 bytů, ve Win64 jen 4 byty. Přejmenoval jsem proto definice unsigned long na uint64_t

Mám také problém s úpravou funkce timems(), kterou jsme zde již řešili v příspěvku "Diskuze: Jak upravit program pro hledání hesla ?"

Udělal jsem si krátký testovací program a něco je tam špatně.

#include <iostream>

//Replacement of the Linux gettimeofday(&end, NULL); function and #include <sys/time.h>
#include <stdio.h>
#include <winsock2.h> // struct timeval
#include <windows.h> // timeGetTime()

typedef unsigned long DWORD;

int gettimeofday(struct timeval* tp, void* tzp);
long long timems(void);

int gettimeofday(struct timeval* tp, void* tzp) {
    DWORD t;

    t = timeGetTime();
    tp->tv_sec = t / 1000;
    tp->tv_usec = t % 1000;

    return 0;
}

long long timems(void) {
    struct timeval end;
    gettimeofday(&end, NULL);
    return end.tv_sec * 1000LL + end.tv_usec / 1000;
}


int main()
{
    while (1) {
        long long rngSeed = timems();
        printf("%lld\n", rngSeed);
        Sleep(2);
    }
}

Hlásí mi to chybu:
LNK2019 Nerozpoznaný externí symbol __imp_timeGetTime odkazovaný ve funkci "int __cdecl gettimeofday(struct timeval *,void *)" (?gettimeofday@@YAHPEAUtimeval@@PEAX@Z) timems

 
Nahoru Odpovědět
26.10.2022 23:04
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:26.10.2022 23:39

To je chyba linkeru, dost pravděpodobně si v projektu nezastavil vše potřebné, jako cesty a soubory. V již zmiňované diskuzi máš celý program, který jsem ti poslal. Ve tvém nejnovějším programu Ti chybí následující řádek který já v programu mám.

#pragma comment( lib, "winmm.lib")
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
26.10.2022 23:39
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:27.10.2022 0:16

Díky, pomohlo to. Nyní bez chyby.

 
Nahoru Odpovědět
27.10.2022 0:16
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 17 zpráv z 17.