Отговори на тема  [ 11 мнения ] 
C въпрос , грешка /предупреждение 
Автор Съобщение
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение 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;
}



Чет Дек 17, 2015 12:01 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение Re: C въпрос , грешка /предупреждение
Проблемът е, че при инициализацията предаваш const променлива към не-const такава. В декларацията на linedescriptorstruct, трябва да направиш singlefieldstruct const.

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


Чет Дек 17, 2015 12:48 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение Re: C въпрос , грешка /предупреждение
не се справих, сложих "const" на

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

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


Чет Дек 17, 2015 1:13 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение Re: C въпрос , грешка /предупреждение
Сега гледам, че едното ти е pointer to pointer, другото array of pointers, което не е един и същи тип.

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


Чет Дек 17, 2015 2:02 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение 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;
}


Чет Дек 17, 2015 2:29 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение 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]|


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


Чет Дек 17, 2015 4:38 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение 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++ някой по-компетентен да каже :)


Чет Дек 17, 2015 5:55 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение Re: C въпрос , грешка /предупреждение
Благодаря за разясненията!
Ще ги обмислям малко по-нататък и сигурно пак ще питам.

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


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


Чет Дек 17, 2015 11:20 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение 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" стои много странно по средата на дефиницията,
а без нея не става.


Чет Дек 17, 2015 11:31 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение Re: C въпрос , грешка /предупреждение
stefan63 написа:
Утреще пробвам с "const"
const struct menudescriptorstruct* menuwork;


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


Пет Дек 18, 2015 12:08 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Дек 19, 2005 12:21 pm
Мнения: 1037
Мнение Re: C въпрос , грешка /предупреждение
stefan63 написа:
Тая дума "const" стои много странно по средата на дефиницията,
а без нея не става.


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

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


Пет Дек 18, 2015 12:16 am
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 11 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 3 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни