Search code examples
cpointersargumentsconstantsfunction-parameter

Function's parameter that is a pointer to an argument that was declared as const, how to handle it?


I'm using MikroC for PIC, I don't know the name of the compiler. I'm using a PIC18F4550. I need to print a list of itens of a menu in a 16x4 LCD. I put here a slice of code, because the code is big to put it here, so, I tried to write here a minimal reproducible example.

The code works in the following whay: I have a stack to store the menus, the menu structure has fields as title and number of itens.

In file main.c

#include "menu.h"

int main(){ 
  unsigned char error;
  error = 0;
  Tstack stackMenus;

  error = menu_push(&stackMenus, &mainMenu);

}

=========================================================

In file menu.c

#include "menu.h"

const Tmenu mainMenu = {
  4,
  "Main Menu"
};

unsigned char menu_push( Tstack *s, PTmenu item ){
  unsigned char error = 0;

  if(s->topo == 9){
    return 1;
  }
  s->pilha[++s->topo] = item;
  return error;
}

======================================================

In file menu.h

struct Smenu {
  unsigned char numberOfItens;
  char *Title;
};
typedef struct Smenu Tmenu;
typedef Tmenu *PTmenu;

struct Sstack {
    PTmenu stack[10];
    signed char top;
};
typedef struct Sstack Tstack;

extern Tmenu mainMenu;

Terro menu_push(Tstack *s, PTmenu item);

I declared mainMenu as const, as pass it as argument to menu_stack. However, the compiler complains saying it is a "Illegal pointer conversion". I tryed to do

unsigned char menu_push( Tstack *s, Tmenu * const item ){ ...}

and

unsigned char menu_push( Tstack *s, const Tmenu * item ){ ...} 

But the same message appears, "Illegal pointer conversion".

How can I handle that ? I need to declare the mainMenu as const because there are others menus and I'm using a microcontroller with a restricted RAM memory size.


Solution

  • This code compiles cleanly under reasonably stringent compilation options. There were quite a lot of trivial changes needed to convert your native language code to the translated English framework. However, I've eliminated PTmenu as a type (as hinted in comments) — the answer to Is it a good idea to typedef pointers? is generally "No".

    menu.h

    typedef unsigned char Terro;
    
    struct Smenu
    {
        unsigned char numberOfItens;
        char *Title;
    };
    typedef struct Smenu Tmenu;
    
    struct Sstack
    {
        const Tmenu *stack[10];
        signed char top;
    };
    typedef struct Sstack Tstack;
    
    extern const Tmenu mainMenu;
    
    Terro menu_push(Tstack *s, const Tmenu *item);
    

    main.c

    #include "menu.h"
    #include <stdio.h>
    
    int main(void)
    {
        unsigned char error;
        Tstack stackMenus = { { 0 }, 0 };
    
        error = menu_push(&stackMenus, &mainMenu);
        printf("Error = %d\n", error);
    }
    

    menu.c

    #include "menu.h"
    
    const Tmenu mainMenu =
    {
        4,
        "Main Menu"
    };
    
    unsigned char menu_push(Tstack *s, const Tmenu *item)
    {
        unsigned char error = 0;
    
        if (s->top == 9)
        {
            return 1;
        }
        s->stack[++s->top] = item;
        return error;
    }
    

    Test compilation (to object file) with GCC 9.1.0 on a MacBook Pro running macOS 10.14.6 Mojave:

    $ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -c menu47.c
    $
    

    There are still issues with the code — the line if (s->top == 9) is diabolical.
    It should be more like if (s->top < 10) except that the 10 should be a name the identifies the size of the stack array in Tstack — I'd probably use a variant on enum { STACK_SIZE = 10 }; and then use that in the array dimension and in the test. That name is a bit too generic for comfort — it could too easily collide with other stack sizes. But that depends on your use case and is taking us far afield. There should be header guards in the menu.h file (#ifndef MENU_H_INCLUDED / #define MENU_H_INCLUDED / …contents of header… / #endif). Capitalization of structure elements is haphazard. The variable error in main() should probably be of type Terro. The return type of the function in menu.c should match the declaration in menu.h — it should be Terro too. Etc.