Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

C въпрос , грешка /предупреждение
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=14228
Страница 1 от 1

Автор:  stefan63 [ Чет Дек 17, 2015 12:01 pm ]
Заглавие:  C въпрос , грешка /предупреждение

Здравейте,
Опитвам се да си сглобя някакво обобщено обработване на менюта на Си,
Долният код го компилирам като C++ и като C .
В първия случай ми дава грешка
"main.cpp|56|error: cannot convert 'const singlefieldstruct* (*)[3]' to 'singlefieldstruct**' in initialization"
Във втория случай му издава предупреждение
||=== Build: Release in pm1 (compiler: GNU GCC Compiler) ===|
main.c|48|warning: initialization from incompatible pointer type
warning: (near initialization for 'line1descriptor.fieldsinlineptrs') [enabled by default]|
Изпълнението ми изглежда коректно.

Това се случва на редовете отбелязани съсъ звездички.

Какво предизвиква тия грешки/предупреждения, какво правя грешно?

Код:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

struct singlefieldstruct
{
unsigned char debugfieldname[15];
unsigned char mystringnumber,myfieldtype,myfieldcountbytes,myfieldoffset,myfieldmaxblink;
};

struct linedescriptorstruct
{
  unsigned char linenamecheck[10];

  unsigned char countfieldsinline;

  struct  singlefieldstruct **fieldsinlineptrs;
  void (*myloadfunction) (void);
  void (*mysavefunction) (void);
  void (*mydisplayfunction) (void);

};

struct menudescriptorstruct
{
unsigned char linecountsinmenu;
struct linedescriptorstruct **linesinmenuPTRS;
};

///    MENU 1 ///
/// line 1 description
const struct singlefieldstruct field1line1={"FieldL1F1:",1,1,1,1,1  };
const struct singlefieldstruct field2line1={"FieldL1F2:",2,3,4,5,6  };
const struct singlefieldstruct field3line1={"FieldL1F3:",1,1,1,1,1  };
const struct  singlefieldstruct *line1fieldsPTRS[]=
{
  &field1line1,
  &field2line1,
  &field3line1
};
void myline1load(void) {};
void myline1save(void) {};
void myline1display(void) {};

const struct linedescriptorstruct line1descriptor=
{ "M1line1",
   3,
  &line1fieldsPTRS,///**************************************
  &myline1load,
  &myline1save,
  &myline1display             };


/// line 2 description
const struct singlefieldstruct field1line2={"FieldL2F1:",1,1,1,1,1  };
const struct singlefieldstruct field2line2={"FieldL2F2:",2,3,4,5,6  };
///const struct singlefieldstruct field3line2={"FieldL2F3:"1,1,1,1,1  };
const struct singlefieldstruct *line2fieldsPTRS[]=
{ &field1line2,
  &field2line2,
};
void myline2load(void) {};
void myline2save(void) {};
void myline2display(void) {};

const struct linedescriptorstruct line2descriptor=
{ "M1line2",
  2,
  &line2fieldsPTRS, ///**************************************
  &myline2load,
  &myline2save,
  &myline2display

};

const struct linedescriptorstruct *menu1linesPTRS[]=
{
     &line1descriptor,
     &line2descriptor
};

const struct menudescriptorstruct mymenu1=
{
2,
&menu1linesPTRS ;///**************************************
};



///#include <conio.h>
void proba1menu1(void)
{
printf("Menu has %d lines\n",mymenu1.linecountsinmenu) ;
int aa,bb;
for (aa=0;aa<mymenu1.linecountsinmenu;aa++)
{


  printf("\n%s _contains_ ",mymenu1.linesinmenuPTRS[aa]->linenamecheck);

  printf(" %d  _fields:\n ", mymenu1.linesinmenuPTRS[aa]->countfieldsinline   );
  printf("\n") ;
  for (bb=0;bb<mymenu1.linesinmenuPTRS[aa]->countfieldsinline;bb++)
  {
   printf ("%s\n",mymenu1.linesinmenuPTRS[aa]->fieldsinlineptrs[bb]->debugfieldname );
  };

};
system("PAUSE");
}



int main()
{
    printf("Hello world!\n");
    proba1menu1();
    return 0;
}


Автор:  radolin [ Чет Дек 17, 2015 12:48 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Проблемът е, че при инициализацията предаваш const променлива към не-const такава. В декларацията на linedescriptorstruct, трябва да направиш singlefieldstruct const.

Също обърни внимание на разликата между: const int*, const int * const, и int const *. В твоя случай май има смисъл и указателя и стойността да са const, ако не смяташ да променяш менюто по време на работа на програмата.

Автор:  stefan63 [ Чет Дек 17, 2015 1:13 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

не се справих, сложих "const" на

const struct singlefieldstruct **fieldsinlineptrs;
struct singlefieldstruct const **fieldsinlineptrs;
struct singlefieldstruct ** const fieldsinlineptrs;
const struct singlefieldstruct ** const fieldsinlineptrs;

Все тая.
Струва ми се ,че трябва да е нещо ,където са звездичките, където се цитират масивите с указатели.
Менютата ще са фиксирани,тоест .всички са конст и с инициализиране.

Автор:  radolin [ Чет Дек 17, 2015 2:02 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Сега гледам, че едното ти е pointer to pointer, другото array of pointers, което не е един и същи тип.

Коато цяло на пръв поглед не мога да вникна точно в логиката ти (може би и поради липсата на коментари).

Автор:  radolin [ Чет Дек 17, 2015 2:29 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Инсталирай си програмката 'cdecl' и после с нея можеш да си тестваш:

Код:
cdecl> explain const struct  singlefieldstruct **fieldsinlineptrs
declare fieldsinlineptrs as pointer to pointer to const struct singlefieldstruct
cdecl> explain const struct  singlefieldstruct *line1fieldsPTRS[]
declare line1fieldsPTRS as array of pointer to const struct singlefieldstruct
cdecl> explain struct  singlefieldstruct* (*fieldsinlineptrs)[]
declare fieldsinlineptrs as pointer to array of pointer to struct singlefieldstruct


Също има разни правила, като четене отзад-напред и спираловидно:
http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html
http://c-faq.com/decl/spiral.anderson.html

Не съм вниквал в логиката, но като се оправят типовете се компилира и при изпълнение извежда това на екрана:

Код:
Hello world!
Menu has 2 lines

M1line1 _contains_  3  _fields:

FieldL1F1:
FieldL1F2:
FieldL1F3:

M1line2 _contains_  2  _fields:

FieldL2F1:
FieldL2F2:


За да се компилира са необходими следните промени (махнал съм и Уиндоус специфичните неща, за да тествам):

Код:
--- stef.orig   2015-12-17 11:09:01.992775465 +0000
+++ stef.c   2015-12-17 11:25:58.480752221 +0000
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <stdlib.h>
-#include <conio.h>

struct singlefieldstruct
{
@@ -14,7 +13,7 @@

   unsigned char countfieldsinline;

-  struct  singlefieldstruct **fieldsinlineptrs;
+  const struct  singlefieldstruct* (*fieldsinlineptrs)[];
   void (*myloadfunction) (void);
   void (*mysavefunction) (void);
   void (*mydisplayfunction) (void);
@@ -24,7 +23,7 @@
struct menudescriptorstruct
{
unsigned char linecountsinmenu;
-struct linedescriptorstruct **linesinmenuPTRS;
+const struct linedescriptorstruct* (*linesinmenuPTRS)[];
};

///    MENU 1 ///
@@ -82,7 +81,7 @@
const struct menudescriptorstruct mymenu1=
{
2,
-&menu1linesPTRS ;///**************************************
+&menu1linesPTRS ///**************************************
};


@@ -96,17 +95,16 @@
{


-  printf("\n%s _contains_ ",mymenu1.linesinmenuPTRS[aa]->linenamecheck);
+  printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);

-  printf(" %d  _fields:\n ", mymenu1.linesinmenuPTRS[aa]->countfieldsinline   );
+  printf(" %d  _fields:\n ", (*mymenu1.linesinmenuPTRS)[aa]->countfieldsinline   );
   printf("\n") ;
-  for (bb=0;bb<mymenu1.linesinmenuPTRS[aa]->countfieldsinline;bb++)
+  for (bb=0;bb<(*mymenu1.linesinmenuPTRS)[aa]->countfieldsinline;bb++)
   {
-   printf ("%s\n",mymenu1.linesinmenuPTRS[aa]->fieldsinlineptrs[bb]->debugfieldname );
+   printf ("%s\n",(*(*mymenu1.linesinmenuPTRS)[aa]->fieldsinlineptrs)[bb]->debugfieldname );
   };

};
-system("PAUSE");
}



Ето и целия код:

Код:
#include <stdio.h>
#include <stdlib.h>

struct singlefieldstruct
{
unsigned char debugfieldname[15];
unsigned char mystringnumber,myfieldtype,myfieldcountbytes,myfieldoffset,myfieldmaxblink;
};

struct linedescriptorstruct
{
  unsigned char linenamecheck[10];

  unsigned char countfieldsinline;

  const struct  singlefieldstruct* (*fieldsinlineptrs)[];
  void (*myloadfunction) (void);
  void (*mysavefunction) (void);
  void (*mydisplayfunction) (void);

};

struct menudescriptorstruct
{
unsigned char linecountsinmenu;
const struct linedescriptorstruct* (*linesinmenuPTRS)[];
};

///    MENU 1 ///
/// line 1 description
const struct singlefieldstruct field1line1={"FieldL1F1:",1,1,1,1,1  };
const struct singlefieldstruct field2line1={"FieldL1F2:",2,3,4,5,6  };
const struct singlefieldstruct field3line1={"FieldL1F3:",1,1,1,1,1  };
const struct  singlefieldstruct *line1fieldsPTRS[]=
{
  &field1line1,
  &field2line1,
  &field3line1
};
void myline1load(void) {};
void myline1save(void) {};
void myline1display(void) {};

const struct linedescriptorstruct line1descriptor=
{ "M1line1",
   3,
  &line1fieldsPTRS,///**************************************
  &myline1load,
  &myline1save,
  &myline1display             };


/// line 2 description
const struct singlefieldstruct field1line2={"FieldL2F1:",1,1,1,1,1  };
const struct singlefieldstruct field2line2={"FieldL2F2:",2,3,4,5,6  };
///const struct singlefieldstruct field3line2={"FieldL2F3:"1,1,1,1,1  };
const struct singlefieldstruct *line2fieldsPTRS[]=
{ &field1line2,
  &field2line2,
};
void myline2load(void) {};
void myline2save(void) {};
void myline2display(void) {};

const struct linedescriptorstruct line2descriptor=
{ "M1line2",
  2,
  &line2fieldsPTRS, ///**************************************
  &myline2load,
  &myline2save,
  &myline2display

};

const struct linedescriptorstruct *menu1linesPTRS[]=
{
     &line1descriptor,
     &line2descriptor
};

const struct menudescriptorstruct mymenu1=
{
2,
&menu1linesPTRS ///**************************************
};



///#include <conio.h>
void proba1menu1(void)
{
printf("Menu has %d lines\n",mymenu1.linecountsinmenu) ;
int aa,bb;
for (aa=0;aa<mymenu1.linecountsinmenu;aa++)
{


  printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);

  printf(" %d  _fields:\n ", (*mymenu1.linesinmenuPTRS)[aa]->countfieldsinline   );
  printf("\n") ;
  for (bb=0;bb<(*mymenu1.linesinmenuPTRS)[aa]->countfieldsinline;bb++)
  {
   printf ("%s\n",(*(*mymenu1.linesinmenuPTRS)[aa]->fieldsinlineptrs)[bb]->debugfieldname );
  };

};
}



int main()
{
    printf("Hello world!\n");
    proba1menu1();
    return 0;
}

Автор:  stefan63 [ Чет Дек 17, 2015 4:38 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Благодаря много Радолине,
Компилира се на Си, много има да чета докато го схвана , особено това

printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);

Не ми е ясно дори как се назовава тая скоба със звездичка.

Опитах и следното:
Код:

struct menudescriptorstruct* menuwork;
void proba2menu1(void)
{
    menuwork=&mymenu1; //***************  warning
///printf("Menu has %d lines\n",mymenu1.linecountsinmenu) ;
    printf("Proba2 ,Menu has %d lines\n",menuwork->linecountsinmenu) ;
    int aa,bb;
    for (aa=0; aa<mymenu1.linecountsinmenu; aa++)
    {
        ///printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);
        printf("\n%s _contains_ ",(*menuwork->linesinmenuPTRS)[aa]->linenamecheck);

        printf(" %d  _fields:\n ", (*menuwork->linesinmenuPTRS)[aa]->countfieldsinline   );
        printf("\n") ;
        for (bb=0; bb<(*menuwork->linesinmenuPTRS)[aa]->countfieldsinline; bb++)
        {
            printf ("%s\n",(*(*menuwork->linesinmenuPTRS)[aa]->fieldsinlineptrs)[bb]->debugfieldname );
        };

    };
    system("PAUSE");
}


Съответно получих предупреждение:
c:\work\probac\pm1\main.c|271|warning: assignment discards 'const' qualifier from pointer target type [enabled by default]|


Отделно - от лшбопитсвто пуснах компилация като Си++. Продължава да дава грешки,
въпреки корекциите. Сигурно още четене :)

Автор:  radolin [ Чет Дек 17, 2015 5:55 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

stefan63 написа:
Благодаря много Радолине,
Компилира се на Си, много има да чета докато го схвана , особено това

printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);

Не ми е ясно дори как се назовава тая скоба със звездичка.



Това си е оператора * - pointer dereference. С него указва, че се интересуваш се от мястото към което сочи указателя, а не от стойността на самия указател.

Скобите са като при всички други операции, за да укажеш приоритетите. Искаме първо на направим dereference (т.е да вземем на където сочи указателя) и чак след това да приложим оператора [] за да вземем елемент от масива. Членът linesinmenuPTRS на структурата mymeny1 ти е "указател към масив от указатели към структури от типа linedescriptorstruct".

Ето нещата едно по едно:

mymenu1 тип: структура от тип menudescriptorstruct

mymenu1.linesinmenuPTRS елемента linesinmenuPTRS от структурата mymenu1
оператор: . достъп до член на структура
тип: указател към масив от указатели към linedescriptorstruct

*mymenu1.linesinmenuPTRS - накъдето сочи linesinmenuPTRS
оператор: * pointer dereference
тип: масив от указатели към структури от типа linedescriptorstruct

(*mymenu1.linesinmenuPTRS)[aa] - елемент аа от въпросния масив
оператор: [] достъп до елемент от масив
тип: указател към структура от типа inedescriptorstruct

(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck - членът linenamecheck на структурата, към която сочи указателят (*mymenu1.linesinmenuPTRS)[aa]
оператор: -> достъп до член на структура, чрез указател
тип: масив от unsigned char

stefan63 написа:
Опитах и следното:
Код:

struct menudescriptorstruct* menuwork;
void proba2menu1(void)
{
    menuwork=&mymenu1; //***************  warning
///printf("Menu has %d lines\n",mymenu1.linecountsinmenu) ;
    printf("Proba2 ,Menu has %d lines\n",menuwork->linecountsinmenu) ;
    int aa,bb;
    for (aa=0; aa<mymenu1.linecountsinmenu; aa++)
    {
        ///printf("\n%s _contains_ ",(*mymenu1.linesinmenuPTRS)[aa]->linenamecheck);
        printf("\n%s _contains_ ",(*menuwork->linesinmenuPTRS)[aa]->linenamecheck);

        printf(" %d  _fields:\n ", (*menuwork->linesinmenuPTRS)[aa]->countfieldsinline   );
        printf("\n") ;
        for (bb=0; bb<(*menuwork->linesinmenuPTRS)[aa]->countfieldsinline; bb++)
        {
            printf ("%s\n",(*(*menuwork->linesinmenuPTRS)[aa]->fieldsinlineptrs)[bb]->debugfieldname );
        };

    };
    system("PAUSE");
}


Съответно получих предупреждение:
c:\work\probac\pm1\main.c|271|warning: assignment discards 'const' qualifier from pointer target type [enabled by default]|


Ами то си ти казва точно за какво те предупреждава - mymenu1 ти е декларирано const, a ти правиш не-const указател към него, чрез който вече можеш да го модифицираш.

stefan63 написа:
Отделно - от лшбопитсвто пуснах компилация като Си++. Продължава да дава грешки,
въпреки корекциите. Сигурно още четене :)


C++ някой по-компетентен да каже :)

Автор:  stefan63 [ Чет Дек 17, 2015 11:20 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Благодаря за разясненията!
Ще ги обмислям малко по-нататък и сигурно пак ще питам.

Цитат:
warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
Ами то си ти казва точно за какво те предупреждава - mymenu1 ти е декларирано const, a ти правиш не-const указател към него, чрез който вече можеш да го модифицираш.


Утреще пробвам с "const"
const struct menudescriptorstruct* menuwork;

Автор:  stefan63 [ Чет Дек 17, 2015 11:31 pm ]
Заглавие:  Re: C въпрос , грешка /предупреждение

Обаче цял ден ме терзае начина ,по който реши проблема с масивите от указатели -
Цитат:
struct linedescriptorstruct
{
unsigned char linenamecheck[10];

unsigned char countfieldsinline;

const struct singlefieldstruct* (*fieldsinlineptrs)[];
void (*myloadfunction) (void);
void (*mysavefunction) (void);
void (*mydisplayfunction) (void);

};


Тая дума "const" стои много странно по средата на дефиницията,
а без нея не става.

Автор:  radolin [ Пет Дек 18, 2015 12:08 am ]
Заглавие:  Re: C въпрос , грешка /предупреждение

stefan63 написа:
Утреще пробвам с "const"
const struct menudescriptorstruct* menuwork;


Да, ако добавиш този const би трябвало да ти изчезне warning-a.

Автор:  radolin [ Пет Дек 18, 2015 12:16 am ]
Заглавие:  Re: C въпрос , грешка /предупреждение

stefan63 написа:
Тая дума "const" стои много странно по средата на дефиницията,
а без нея не става.


Предполагам, че по средата на дефиницията на структурата имаш предвид. Защо да е странно? Тя се отнася в случая само за елемента fieldsinlineptrs.

По принцип може да махнеш всички const-ове и нещата ще си работят. Ползата от тях е, че ако си казал, че нещо не трябва да се променя, а после някъде из кода се опиташ да го промениш компилатора веднага ще ти изпищи. Съответно ще си хванеш грешката много по-рано и няма да загубиш дни и нощи в дебъгване на мистериозен проблем. Също евентуално може и да помогне на компилатора да оптимизира кода или къде се съхраняват променливите в някои случаи.

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/