How can I convert char pointer to __uint8_t array in C? - c

I need to convert a string (char*) to an array of __uint8_t. I know the latter is an alias of unsigned char but I can't figure it out how to proper convert it.
Example:
char *ssid = "XXXXX";
This is need cause I have to call an API that accepts only an array of __uint8_t and not char*.
struct WifiConfig {
uint8_t ssid[32];
uint8_t password[64];
};
struct WifiConfig wifi_config;
wifi_config.ssid = ???
If I try to cast:
wifi_config.ssid = (__uint8_t *) ssid;
I get the follow error:
error: assignment to expression with array type
wifi_config.ssid = (__uint8_t *) ssid;
Sorry if that's a silly question, last time I've played with C I was a teen.
Thanks in advance!

Just cast:
const char *name = "My Full Name";
yourAPIFunction((__uint8_t *) name);
Note: this violates const-correctness. You have to make sure yourAPIFunction doesn't mutate name. If it does, then you'll need to memcpy (and free!) it to a local variable, and provide it that, so its mutations don't effect the pooled-string used by any other users of "My Full Name".
Response to your (completely different) updated question:
Those arrays have their storage in-line, they're not pointers to the heap like a typical char *.. You need to copy the contents of your string into them:
// ssid must be at most 31 chars (plus NUL terminator)
// password must be at most 63 chars (plus NUL terminator)
struct WifiConfig new_wifi_config(char *ssid, char *password) {
struct WifiConfig wifi_config;
memcpy(wifi_config.ssid, ssid, strlen(ssid)+1)
memcpy(wifi_config.password, ssid, strlen(ssid)+1)
return wifi_config;
}

I need to convert a string (char*) to an array of __uint8_t. I know
the latter is an alias of unsigned char but I can't figure it out how
to proper convert it.
Being pedantic -- because it matters here -- a C string is not a char *. Rather, it is a null-terminated array of char. These are accessed and handled primarily via pointers of type char *, largely because that's how one works with arrays in C.
Thus, no, you do not want to convert a char * to an array. It appears that what you want to do is copy the contents of the array to which it points. For your particular purpose I would use the strncpy() function:
strncpy((char *) wifi_config.ssid, ssid, sizeof(wifi_config.ssid));
Note well that with that code, if ssid is longer than wifi_config.ssid can accommodate then the latter will end up being unterminated, and that otherwise its tail will be filled out with null bytes. Given the type of that array, such behavior may be precisely what is needed. If you want to ensure null termination, however, then simply overwrite the last byte of the array with a 0 after the strncpy().

Related

C string setting character array to argv[1]

if I have a program as follows:
int main(int argc, char** argv) {
char s[32] = argv[1];
printf("entered char is %s\n", s);
}
Why do I get an error: array initializer must be an initializer list or string literal, during compile time?
Isn't argv[1] a string and isn't is legal to do
char s[32] = "A test string"
You can't initialize an array using a pointer like that. Instead you have to copy the string after declaration:
char s[32];
strcpy(s, argv[1]);
Note that you should really check if at least one argument is provided before doing that (by checking argc). Also note that unless you want to modify the string provided in the argument, there's really no need to keep a second copy of the string.
Oh and you might want to use strncpy instead of plain strcpy, to avoid a possible buffer overflow situation. Remember that strncpy will not terminate the string if the source is to long, so you need to do it explicitly.
Expression char s[32] = argv[1]; causes error because by doing s=argv[1] you are trying to change base address of s, which is not possible as s is constant pointer.
Use strcpy() to copy argv[1] into s
char s[32];
strcpy(s,argv[1]);
Asking a question like this means - you are not aware of certain rules. In C, there are a few possible ways you can initialize an array. And the compiler told you about that when it saw it violating the rule. It says it must be string literal or initializer list. The one you provided is not any of this. It is simply a pointer and you can't initialize an array by putting it in the right side of the = assignment operator.
char s[]="hello";
char s[]={'h','e','\0'};
Select one as shown above. First is using literal and second using initializer list. In your case you can't use any of these - what's the way? strcpy at your rescue. Before you use like the other answer showed make sure buffer is big enough to hold stuff you copy.

Google Protobuf-c repeated strings

My Google protobuf-c proto file looks like this:
message foo{
required uint32 addresscount= 1;
repeated string destination_hops= 2;
}
I want an array of strings and addresscount is supposed to give the count of array elements.
The generated protobuf-h file is
struct _foo
{
ProtobufCMessage base;
uint32_t addresscount;
size_t n_destination_hops;
char **destination_hops;
};
I assume that n_destination_hops is the number of times the string destination_hops appears in the message. I had kept addresscount for that purpose and i guess thats not required. My question is this:
char **destination_hops is a pointer to an array of char * pointers. Each index can be of different length. How will protobuf know the size of each char * pointer when it has packed this into a stream. Does protobuf assume that all destination_hops would be of the same size and is that given by size_t n_destination_hops?
DOUBT 2:
char ** destination_hops is an array of char * pointers.
This means i can look at it as char *destination_hops[0], char *destination_hops[1], etc
If this is correct then shouldn't i be able to set char *destination_hops[0] = "abc".
When i do that i get a segmentation fault.
Any idea why?
I assume that n_destination_hops is the number of times the string destination_hops appears in the message.
Yep.
I had kept addresscount for that purpose and i guess thats not required.
Right.
char **destination_hops is a pointer to an array of char * pointers. Each index can be of different length. How will protobuf know the size of each char * pointer when it has packed this into a stream.
In the wire representation of the string, it is preceded by the string's length, coded as a packed integer. In memory, they are just ordinary zero-terminated C strings, so:
NUL is not a valid character in the string
the length can be computed with strlen
Protobuf requires that the value of a string be a sequence of UTF-8 encoded characters. If you want to include NUL or bytes which are not part of a valid UTF-8 sequence, use bytes instead of string. If you do that, the in-memory datastructure will include an explicit length.
Shouldn't i be able to set char *destination_hops[0] = "abc"
I suppose you mean that you should be able to write:
destination_hops[0] = "abc";
That's valid C, but it requires that destination_hops have at least one element. A newly initialized foo will have n_destination_hops = 0; and destination_hops = NULL;, in which case trying to access destination_hops[0] will try to dereference NULL, which is a segfault. (Or UB, if you prefer.9

Convert struct field to unsigned char string

I'm on an embedded system so do not have access to a most of the standard library. I have a struct which contains char values.
I have a simple print function which simply outputs an unsigned char string to an attached screen. It does not support format specifiers like printf does.
This is the struct:
typedef struct my_options{
char test;
} my_options;
And this is where I'm trying to output the value:
struct my_options options;
print(options.test); //Here I get "implicit conversion of int to ptr"
How do I achieve this?
Create a char array to hold your char and then print it:
char wrapper[2];
wrapper[0] = options.test;
wrapper[1] = '\0';
print(wrapper);
Create a temporary 2-character long string that has the character to print, and then the terminator. Then pass that string to your print() function:
void print_options(const struct my_options *opt)
{
char tmp[] = { opt->test, '\0' };
print(tmp);
}
your member test if of the type char, where the print function expects an argument of the type const char * (assuming the const bit here, but that's what I'd expect, this as an asside). Passing the address of test then would seem like the appropriate solution, but is it?
No, of course it isn't. There is no absolute guarantee that the next byte after test will be '\0' (a string terminating char). What you, then, ought to do is create a wrapper string:
char char_wrapper[2] = {};//initializes according to standard
//but as Lundin pointed out, self-documenting code is important:
char_wrapper[0] = options.test;?
char_wrapper[1] = '\0';//explicit, so it's clear what this code does
print(char_wrapper);
That should work just fine.
You can, of course, write this as a one-liner:
char char_wrapper[2] = {options.test, '\0'};//same as before, only in 1 statement
print(char_wrapper);//print "string"
That should do it, really. You don't even have to explicitly write the terminating char, since the standard specifically states:
An array of character type may be initialized by a character string literal, optionally
enclosed in braces. Successive characters of the character string literal (including the
terminating null character if there is room or if the array is of unknown size) initialize the
elements of the array.
6.7.8 Initialization cf p. 138, semantics, point 14
Be that as it may, I'd still prefer to browse the web, or just set about writing your own minor implementation of printf so you can use format specifiers. Heck, it's one of the first exercises in the K&R book, and there's tons of solutions floating about on the net. check those out, and adapt them to your specific needs.
Or, perhaps define print to accept a size_t argument, to specify how many chars you want to pass to the output stream. and call it like so print(options.test, 1);
print is looking for a char*. You are passing an char which can also be represented as an int. Thus, the function is trying to implicitly convert an int to a pointer as it is telling you.
char ptr[2];
ptr[0] = options.test;
ptr[1] = '\0';
Would wrap the char into a char array, which in C will decay into a pointer when you pass it to a function.

How is a string literal equal to char*, and how should I take a string as a parameter

I have seen in several pieces of code a string declared as char*. How does this work, surely it is a pointer to a single char, not an array of chars which makes up a string. If I wished to take string input to a method that would be called like this:
theMethod("This is a string literal");
What datatype should the parameter be?
surely it is a pointer to a single char, not an array of chars
It's a pointer to the first character of an array of char. One can access each element of the array using a pointer to its first element by performing pointer arithmetic and "array" indexing.
What datatype should the parameter be?
const char *, if you don't wish to modify the characters from within the function (this is the general case), and char * if you do.
This is a common beginner-C confusion. A pointer to any type, T *, is ambiguously either a pointer to a single object of type T, or a pointer to an element within a linear array of objects of type T, size unspecified. You, the programmer, are responsible for knowing which is which, and passing around length information as necessary. If you get it wrong, the compiler stands by and watches as your program drives off the undefined-behavior cliff.
To the extent C has strings (there is a strong case to be made that it doesn't really) they take shameless advantage of this ambiguity, such that when you see char * or const char * in a C program, it almost always will be a pointer to a string, not a single char. The same is not true of pointers to any other type.
per definition is "string" of type char * (or unsigned char * or const char *) however, it is a pointer to the first character of that character chain (i dont want to use the words array or vector). The Difference is to see in char: 'x' (single quote)
this is good old c programming (sometimes i could cry for loosing it)
char *p = "i am here";
for (q=p; ++q; *q) { // so lets start with p walk through and end wit the /0 after the last e
if (*q=='h') { // lets find the first 'h' and cut the string there
*(q-1)=0;
break;
}
}
i used no const and other probs here, i just try to clearify

How to properly initialize a string

How would I go about defining the following string for the following function?
As of now I get the warning:
C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'
and the error:
C2166: l-value specifies const object.
Both in the third line of the code below:
uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);
uint32_t protobuf_writeString(uint8_t *out,const char * str)
{
if (str == NULL)
{
out[0] = 0;
return 1;
}
else
{
size_t len = strlen (str);
size_t rv = uint32_pack (len, out);
memcpy (out + rv, str, len);
return rv + len;
}
}
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
This is not valid code. You are trying to assign to a const variable, which is illegal. Then you are trying to assign an array of characters to a character. And finally, even if you had a non-const array of characters of the right size, you still can't assign arrays, because they're not first-class values.
Try using
char *stringaling = malloc(sizeof(uint32_t));
strcpy(stringaling, "fun");
...instead, and see if that doesn't work better. Note, however, that it's pretty much accidental that (at least usually) sizeof(uint32_t) happens to be the right size to hold "fun". You normally don't want to do that.
Alternatively, you may want:
char const *stringaling = "fun";
or:
char stringaling[] = "fun";
The assignment you had won't work though -- C has only the very most minimal support for strings built into the language; most operations (including copying a string) are normally done via library functions such as strcpy.
"fun" is a string literal, which is essentially a const char *.
stringaling is also a const char *, so your third line is trying to assign a const char * to a const char, which is not going to fly.
If it's a constant string, you can just do this:
const char *stringaling = "fun";
If your input string is dynamic, you can do this:
char *stringaling= (char *) malloc(strlen(inputString)+1);
strcpy(stringaling, inputString);
Obviously, if you malloc it, you need to free it, or feel the wrath of a memory leak.
If you really want to initialize the char *, you could write this instead:
const char *stringaling = "fun";
And here's some reference.
without all the stuff you can also use:
newval = protobuf_writeString (buffer, "fun" );
First problem:
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
Several problems on this line.
First of all, you don't want to declare stringaling as const char *; you will not be able to modify whatever stringaling points to (IOW, *stringaling will not be writable). This matters since you want to copy the contents of another string to the location pointed to by stringaling. Drop the const keyword.
Secondly, malloc(sizeof(uint32_t)) just happens to allocate enough bytes (4) for this particular string, but it's not clear that you meant to allocate 4 bytes. When allocating memory for an array (and strings are arrays), explicitly indicate the number of elements you intend to allocate.
Finally, casting the result of malloc is considered bad practice in C. The cast will suppress a useful diagnostic message if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope. As of the 1989 standard, malloc returns void *, which can be assigned to any other object pointer type without needing to cast. This isn't true in C++, so a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
So, change that line to read
char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
// in this case that's redundant since
// sizeof (char) == 1
where LEN is the number of chars you want to allocate.
The general form for a malloc call is
T *p = malloc (N * sizeof *p);
where T is the base type (int, char, float, struct ..., etc.), and N is the number of elements of type T you want to allocate. Since the type of the expression *p is T, sizeof *p == sizeof(T); if you ever change the type of p, you don't have to replicate that change in the malloc call itself.
Second problem:
*stringaling = "fun";
Again, there are several issues at play. First, you cannot assign string values using the = operator. String literals are array expressions, and in most contexts array expressions have their type implicitly converted ("decay") from "N-element array of T" to "pointer to T". Instead of copying the contents of the string literal, you would be simply assigning a pointer to the first character in the string.
Which would "work" (see below), except that you're dereferencing stringaling in the assignment; the type of the expression *stringaling is const char (char after making the change I indicated above), which is not compatible for assignment with type char *. If you drop the dereference operator and write
stringaling = "fun";
you'd fix the compile-time error, but now you have another problem; as mentioned above, you haven't copied the contents of the string literal "fun" to the memory block you allocated with malloc; instead, you've simply copied the address of the string literal to the variable stringaling. By doing so, you lose track of the dynamically-allocated block, causing a memory leak.
In order to copy the string contents from one place to another, you'll have to use a library function like strcpy or strncpy or memcpy, like so:
strcpy(stringaling, "fun");
If stringaling doesn't need to live on the heap (for example, you're only using it within a single function and deallocating it before returning), you could avoid memory management completely by declaring it as a regular array of char and initializing it with "fun":
char stringaling[] = "fun";
This is a special case of initializing an array in a declaration, not an assignment expression, so the = does copy the contents of the string literal to the stringaling array. This only works in an array declaration, however. You can later modify the array with other string values (up to 3 characters plus the 0 terminator), but you'd have to use strcpy again:
strcpy(stringaling, "one");
If you don't need to modify the contents of stringaling, you could just do
const char *stringaling = "fun";
This copies the address of the string literal "fun" to the variable stringaling. And since attempting to modify the contents of a string literal invokes undefined behavior, we do want to declare stringaling as const char * in this case; that will prevent you from accidentally modifying the string literal.

Resources