Strona 1 z 1

Lista SLL - warning w działającym kodzie

: sobota 05 kwie 2025, 16:12
autor: Antystatyczny
Cześć, od kilku dni siedzę nad listą jednokierunkową i mam pewien problem dotyczący ostrzeżenia, które generowane jest przez środowisko Visual Studio. Najpierw przedstawię, o co mi chodzi:

Kod: Zaznacz cały

static void List_destroy(node_t** n)
{
   node_t *temp = NULL;

#ifdef DEBUG
   int cnt = 0;
#endif /* DEBUG */

   if ((*n) != NULL)
   {
      do
      {
         temp = (*n)->next;// <--- C6001 Używanie niezainicjowanej pamięci „*temp”.

         free((*n));

#ifdef DEBUG
         printf("memory freed %d times\n", ++cnt);
#endif /* DEBUG */

         *n = temp;
      }while (*n != NULL);
   }
}


Kod się kompiluje bez błędów i ostrzeżeń, a program działa poprawnie, czyli dynamicznie alokuje pamięć dla kolejnych węzłów, wyświetla ich listę, na koniec niszczy wszystkie węzły i uwalnia pamięć. W Visual Studio mam możliwość skorzystania z usługi Copilot, więc z niej skorzystałem i otrzymałem, co następuje:

Aby naprawić błąd C6001, musisz upewnić się, że zmienna temp jest zainicjowana przed jej użyciem. W tym przypadku, problem polega na tym, że temp jest używana przed przypisaniem do niej wartości. Możesz to naprawić, inicjując temp przed zwolnieniem pamięci. Oto poprawiona wersja funkcji List_destroy:

Kod: Zaznacz cały

static void List_destroy(node_t** n)
{
   node_t *temp = NULL;

#ifdef DEBUG
   int cnt = 0;
#endif /* DEBUG */

   while (*n != NULL)
   {
      temp = (*n)->next; // Zainicjuj temp przed zwolnieniem pamięci <--- tutaj nadal mam to samo ostrzeżenie

      free(*n);

#ifdef DEBUG
      printf("memory freed %d times\n", ++cnt);
#endif /* DEBUG */

      *n = temp;
   }
}







Jak widać wywalony jest if sprawdzający, czy wskaźnik n nie jest pusty, ale to sprawdzenie i tak następuje podczas wejścia do pętli while. Tak czy siak nadal wyświetlane jest ostrzeżenie o tej samej treści i dotyczące tej samej zmiennej. Kod proponowany przez Copilot również działa poprawnie i kompiluje się bez ostrzeżeń. Ktoś ma jakieś pomysły, co z tym zrobić? Visual studio jest nadgorliwe?

Re: Lista SLL - warning w działającym kodzie

: niedziela 06 kwie 2025, 11:53
autor: xor
Czesć! n może być niezainicjowane a nie jest sprawdzane.

Re: Lista SLL - warning w działającym kodzie

: niedziela 06 kwie 2025, 17:10
autor: Antystatyczny
W funkcji mam test

Kod: Zaznacz cały

if ((*n) != NULL)

przed wejściem w pętlę, a sama pętla wykonuje się dopóki

Kod: Zaznacz cały

while (*n != NULL);

Re: Lista SLL - warning w działającym kodzie

: poniedziałek 07 kwie 2025, 06:16
autor: j23
W Twoim oryginalnym kodzie (ten zaraz podany na wstępie Twojego postu Anty) jest warunek if, który sprawdza zmienną "n", a pod koniec pętli do-while jest TEN SAM WARUNEK, który też sprawdza zmienną "n". Jasne, że kod działa poprawnie i będzie działał. Nie wiem czy Visual Studio jest nadgorliwe, ale na mój rozumek to VS może nie pasować to, że używasz dwóch "spadochronów" przeciw zmiennej "n" PODCZAS GDY wg VS można to by zrobić za pomocą jednego i DLATEGO Visual Studio proponuje pętlę while (a nie do-while), bo w pętli while warunek jest sprawdzany ZANIM program wejdzie w pętle while (a konkretnie to zanim instruction pointer z wykonywanego programu wejdzie w pętle while).

Twój program Anty
(pseudokod - 6 linijek):
[START]
[CZY ZMIENNA N JEST PUSTA?]
{
[WEJDŹ DO PĘTLI WHILE...]
<JEDNORAZOWA_ITERACJA_PĘTLI_WHILE>
[...I WYKONUJ PĘTLĘ WHILE DOPÓKI N NIE STANIE SIĘ PUSTA]
}

[END]

Modyfikacja zaproponowana przez Copilota VS (żeby kod był wydajniejszy? a może VS jest rzeczywiście nadgorliwy? ;) )
(pseudokod - 4 linijki):
[START]
[ZACZNIJ WYKONYWAĆ PĘTLĘ WHILE POD WARUNKIEM ŻE N NIE JEST PUSTA]
{
<JEDNORAZOWA_ITERACJA_PĘTLI_WHILE>
}

[END]

Nie jestem pewny do końca czy moje rozumowanie jest tutaj poprawne, ale warning (ostrzeżenie) od VS ma chyba na celu sprawić, żeby kod był po prostu wydajniejszy.

Na stackoverflow trochę o tym piszą i podają rozwiązanie co zrobić, żeby rozkazać VS aby zamknął japę z niepotrzebnymi ostrzeżeniami, a konkretnie jest tam fragment (przetłumaczone przy pomocy https://translate.google.com):
To jest bardzo fałszywy alarm i nadal istnieje nawet w MSVC 2019. Nie ma możliwości, aby zmienna t.p mogła zostać niezainicjowana.

W rzeczywistości nie ma możliwości, aby mogła dotrzeć do instrukcji free() bez zainicjowania jej wartością różną od NULL. Ale nawet jeśli dopuścisz możliwość, że kompilator nie wie, że funkcja exit() nie zwróci, to jest to w zasadzie nieistotne. Niezależnie od tego, czy zwróci, czy nie, struktura nadal będzie zainicjowana czymś i w każdym przypadku free(NULL) jest całkowicie legalne.

Usunięcie if .. exit nie ma wpływu na ostrzeżenie, więc wątpię, aby to był problem. Bardziej prawdopodobne jest, że MSVC po prostu agresywnie zgłasza ostrzeżenia i najlepszym sposobem, aby przestać Cię to niepokoić, jest po prostu to zignorować.

Nie mam na myśli, że ignorujesz ostrzeżenie (ja nigdy nie mógłbym tego zrobić ze względu na moją naturę), mam na myśli powiedzenie MSVC, żeby się zamknął:

while (1) {
MyStruct t = Test();

// MSVC wrongly reports this as using uninitialised variable.
#pragma warning(push)
#pragma warning(disable: 6001)
free(t.p);
#pragma warning(pop)
}

Innymi słowy gościu ze stackoverflow podaje rozwiązanie typu brute-force aby poprzez dyrektywę preprocesora "#pragma" kazać VS aby nie generował denerwującego ostrzeżenia o błędzie 6001.

Re: Lista SLL - warning w działającym kodzie

: poniedziałek 07 kwie 2025, 17:03
autor: Antystatyczny
j23 pisze:Modyfikacja zaproponowana przez Copilota VS (żeby kod był wydajniejszy? a może VS jest rzeczywiście nadgorliwy?


Możliwe, choć z opisu wynikało, że copilot poprawia mój błąd braku inicjalizacji zmiennej. Zerknąłem sobie na Stackoverflow i przeczytałem cały wątek. W zasadzie u mnie jest taka sama sytuacja i chyba skorzystam z chwilowego wyłączenia ostrzeżenia 6001:

Kod: Zaznacz cały

#pragma warning(push)
#pragma warning(disable: 6001)
free(*n);
#pragma warning(pop)


W każdym razie serdeczne dzięki. Szukałem, ale na ten wątek nie trafiłem.

Re: Lista SLL - warning w działającym kodzie

: piątek 11 kwie 2025, 17:56
autor: xor
Antystatyczny pisze:W funkcji mam test

Kod: Zaznacz cały

if ((*n) != NULL)



Ja mówię o teście

Kod: Zaznacz cały

n != NULL

Od któregoś nowszego standardu C jest jakaś składnia wskazująca kompilatorowi, że parametr przekazany do funkcji jest zawsze valid, Visual, zdaje się ma też jakieś swoje dyrektywy. W tej postaci fukcji takiej pewności nie ma, n może być NULL i podejrzewam, że tego się czepia. Ale VS ni w ząb nie umiem więc pewnie się mylę. :-)

Re: Lista SLL - warning w działającym kodzie

: piątek 11 kwie 2025, 18:09
autor: Antystatyczny
xor pisze:Ale VS ni w ząb nie umiem więc pewnie się mylę.


No właśnie ja też nie jestem biegły w tym środowisku, a w dodatku programuję wyłącznie hobbystycznie. W każdym razie, jeśli natrafię na jakiś lepszy opis lub rozwiązanie problemu, ewentualnie napiszę lepszy kod (bo to moje pierwsze podejście do SLL), wrzucę informację do wątku. Póki co zawiesiłem warning 6001 wokół jednej linijki kodu i mam spokój :)

Re: Lista SLL - warning w działającym kodzie

: wtorek 04 lis 2025, 21:06
autor: Antystatyczny
Po jakimś okresie bezczynności w kwestii list jednokierunkowych wróciłem dziś do tematu, bo muszę poukładać widgety w listach, żeby zautomatyzować propagację zdarzeń. No i tym razem udało mi się bez problemu napisać lepszy kod, czyli:

Kod: Zaznacz cały

void List_destroy(node_t** n)
{
   while (*n != NULL)
   {
      node_t* tmp = *n;
      *n = tmp->next;
      free(tmp);

   }
}


Brak ifa sprawdzającego obecność wskaźnika, bo pętla while na wejściu zrobi to automatycznie. W związku z tym tmp zostanie zainicjalizowana poprawnym adresem, więc środowisko VS również przestało się czepiać. Takie proste, a tyle czasu mi zajęło. Temat rozwiązany, pozdro!