1

In C we cannot assign a char** to const char *const * because of this problem. So, what's the base way to declare a function accepting an array of strings?

My input parameters may be of any types, including:

  • char **
  • const char **
  • ...
frogatto
  • 28,539
  • 11
  • 83
  • 129

2 Answers2

1

I end up using the Antti Haapala's suggestion (thank you Antti Haapala!). Using const char * const * as the argument type and explicitly casting incompatible types.

#define STR_ARR(v) _Generic((v),             \ 
    char**: (const char *const *)(v),        \
    char *const *: (const char *const *)(v), \
    default: (v))

void foo(const char * const * strings);

Usage:

char **strs1;
foo(STR_ARR(strs1));

const char **strs2;
foo(STR_ARR(strs2));
frogatto
  • 28,539
  • 11
  • 83
  • 129
  • You shouldn't allow a default clause. And I'd use a wrapper macro around the specific function instead, then in API documentation use the macro name instead of the actual function name. – Lundin Nov 18 '19 at 14:45
  • @Lundin I don't think the default clause causes a problem as the other types will be checked by the compiler. I only whitelisted the required types. – frogatto Nov 18 '19 at 14:49
  • There's a scary amount of C programmers that follow the rule "when in doubt cast to void pointer". So `foo((void*)my_wildly_incompatible_misaligned_pointer);` is a likely scenario. – Lundin Nov 18 '19 at 14:53
1

The best way is to have the caller sort their code out. Otherwise you can do a type-safe wrapper macro along the lines of this:

#include <stdio.h>

void str_print_ro (const char* str_arr[], size_t n)
{
  for(size_t i=0; i<n; i++)
  {
    puts(str_arr[i]);
  }
}

#define str_print(arr,n) _Generic((arr), \
  const char** : str_print_ro,           \
  char**       : str_print_ro) ((const char**)(arr), n) 

int main (void)
{
  char* arr[] = {"hello", "world"};
  str_print(arr, sizeof arr/sizeof *arr);  
}

It probably doesn't make much sense to const-qualify the pointers themselves. If you for some reason need that too, then const char* const str_arr[] should sort it, and that one can be converted to from char** and const char** both.

Lundin
  • 195,001
  • 40
  • 254
  • 396