2

My C-API takes an array of uint8_t's as config parameter. I'm arriving at its doorsteps with a const char*. How do I now copy the chars over to the uint8_t array in the most unproblematic way? Here's what I've got (contrived ofc):

Demo

#include <cstdint>
#include <cstring>
#include <cstdio>

struct config
{
    uint8_t ssid_[32];
};


auto set_ssid(const char* ssid) {
    // I know this fn has no sideeffects but assume for demonstration
    // purposes that cfg is only initialized here
    config cfg;

    std::strncpy(static_cast<char*>(&cfg.ssid_), ssid, 32);
}

int main()
{
    set_ssid("ComeOver");
}

But this doesn't work as none of the pointer is of void* type:

<source>:14:18: error: invalid 'static_cast' from type 'uint8_t (*)[32]' {aka 'unsigned char (*)[32]'} to type 'char*'
   14 |     std::strncpy(static_cast<char*>(&cfg.ssid_), ssid, 32);
      |              

Is it safe to reinterpret_cast here?

glades
  • 3,778
  • 1
  • 12
  • 34
  • `std::strncpy` is C API, you should use some idomatic C++ (`std::copy`?). Note that your `set_ssid` function doesn't have any observable effects, so it is not clear what you are trying to achieve. Also I do not like design of this API, also use of it looks like indentation for UB. – Marek R Oct 13 '22 at 14:36
  • Possible approach: https://godbolt.org/z/78WxaWqG8 as you can see compiler sees there is no side effects in `set_ssid` and removed its code. So please provide code which does something meaningful. – Marek R Oct 13 '22 at 14:43
  • See https://stackoverflow.com/questions/10151834/why-cant-i-static-cast-between-char-and-unsigned-char – Captain Giraffe Oct 13 '22 at 14:46
  • @MarekR Thank you, copy_n didn't come to my mind. I know that the function has no sideffects but i zoomed in onto the problematic matter for demonstration purposes and left all baggage out. – glades Oct 13 '22 at 14:46
  • @MarekR That reads out-of-bounds. – user17732522 Oct 13 '22 at 16:30
  • @glades What guarantees are there that the string referred to by the `const char*` pointer fits into the array? What is supposed to happen if it doesn't fit? Is it necessary to pass it by `const char*` or wouldn't it be possible to pass as e.g. array (reference)? – user17732522 Oct 13 '22 at 16:32
  • Also as far as I can tell SSIDs must specify their length explicitly and are allowed to contain null characters, so they cannot be specified as null-terminated byte strings. – user17732522 Oct 13 '22 at 16:35
  • @Marek, using a C API is perfectly fine. ```strncpy()``` is not equivalent to ```copy_n()``` because the former breaks a loop earlier at a null character.(Although it does not ensure a terminating null.) – relent95 Oct 13 '22 at 16:43
  • @relent95 yes I'm aware that compiler will generate same code. `std::copy` version is more C++ idiomatic. I find this more readable then `strncpy` which needs casting. – Marek R Oct 13 '22 at 21:11
  • @user17732522 Yes you are right and I was warning about this in first comment (but didn't fix it in example I should) - this UB is a result of shortcoming in API design. Since there is no context what this code should do it is impossible to improve API. – Marek R Oct 13 '22 at 21:13

1 Answers1

0

You should use cfg.ssid_ for the destination buffer instead of &cfg.ssid_. Also you should use reinterpret_cast instead of static_cast, because char * and unsigned char *(uint8_t *) are not pointer-interconvertible.(It's a rule refining various casts. See static_cast conversion.)

So this is recommended.

std::strncpy(reinterpret_cast<char*>(cfg.ssid_), ssid, 32);
// Or simply
std::strncpy((char *)(cfg.ssid_), ssid, 32);
relent95
  • 3,703
  • 1
  • 14
  • 17
  • I mean, out of possible conversions between pointers to a POD, there are pointer-interconvertible cases and not pointer-interconvertible cases. – relent95 Oct 13 '22 at 17:03
  • Yes, but all of these conversions go through `void*` anyway. `reinterpret_cast` between pointers is also just a sequence of `static_cast`s through `void*`. The objects here are not pointer-interconvertible, true, but in order for this to work it is important whether the pointer may _alias_ the object (which it may). – user17732522 Oct 13 '22 at 17:12