Convert struct field to unsigned char string - c

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.

Related

Why we didn't use * during dereferencing the pointer?

In the below code, we get a pointer from strdup(source) and we store it in a pointer named target.
Now, when we print the string using pointer, we don't add * at the beginning of the pointer: why is it so? As I studied whenever we want to dereference any pointer we use *pointer_name. If we add * in the below code, we get an error.
I am very beginner, so pls ans in easy words.
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "Programming";
char* target = strdup(source);
printf("%s\n",target);
return 0;
}
printf expects a char pointer in the place of the %s specifier.
https://en.cppreference.com/w/c/io/fprintf
char* target = strdup(source);
printf("%s\n",target);
Why we don't use *target in the code above?
The explanation is quite simple, as already stated in previous answers: target has type char pointer, which is exactly what printf() wants in the above call.
Now, printf() is a little complicated because its semantic is not simple - basically it accepts zero or more arguments after the first, of any type (possibly applying promotion). But if we use strdup() again, maybe it is simpler:
char* target2 = strdup(target);
Here, if you wrote strdup(*target), the compiler might warn that you are passing a char instead of a pointer to char.
strdup() returns a char*, hence the char* type of target. target holds a pointer to the first character in an array of chars. printf("%s", string) expects string to be a char*, so there’s no reason to do anything to target; just pass it to printf().
If you dereferenced target, you would get a single char (P in this case). printf() would then complain that you had supplied a character instead of a string (pointer to character). Even worse, the program could compile, and then printf() would try to print the string at address P (0x50), which would result in probably unwanted behaviour.
When working with arrays—a string is a type of array—you rarely want to dereference the array.

How can I convert char pointer to __uint8_t array in 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().

How do i determine the length of a string if it's declared as const char *str?

I have the following function structure
int function(const char *str)
{
return 0;
}
I never could fully understand why people use char *str rather than simply string str. So I am guessing this basically means that the argument is the pointer to the first character of the string. How do I determine the length of the string str given that argument?
What I've tried is to iterate through str, if I hit a NULL or "" or '', then that will be the end of it. However, none of these types are compatible for comparison. Please give me some clue regarding this. Thx!
Jamesdlin's answer is good, but to answer your question about comparisons, you would use '\0', IE:
char* a = "a";
int size = 0;
while (a[size] != '\0')
size++;
NULL is a pointer macro, "" is an empty character array (Though it has an implicit '\0', so you could theoretically do strcmp(a, "");), and '' is just an empty character, I'm not sure that it's even a valid statement.
Also, std::string is a C++ class and does not exist in the C standard library.
In C, strings are typically NUL-terminated. For NUL-terminated strings, you can simply call strlen(str).
I never could fully understand why people use char *str rather than simply string str.
There is no string type in C. You could add a typedef:
typedef char* string;
But adding typedefs for pointer types is generally a bad idea (because now you need a separate typedef for const char*; const string would not be the same thing).
And while doing so might seem like a good idea, in practice it will obscure your code since char*/const char* for strings is the norm.
You are almost correct, char *str is a pointer to the first character of a char array, but C has no predefined string type - it's just a zero-terminated char array. Instead of trying to write a function (although it would be a good student exercise), just call the library function in <string.h> with strlen (str); which takes a pointer to the character array. You don't pass *str or &str but just str if it is a declared array variable. If memory was allocated dynamically, you pass the allocated pointer, so if the pointer was declared as char *memstr you pass it as memstr. As others have said, it's best not to try to define a string, better to understand how the char array works.

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

pointer of char and int

Hi I have a simple question
char *a="abc";
printf("%s\n",a);
int *b;
b=1;
printf("%d\n",b);
Why the first one works but the second one doesnot work?
I think the first one should be
char *a="abc";
printf("%s\n",*a);
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
Thanks
Ying
Why the first one works but the second one doesnot work?
Because in the first, you're not asking it to print a character, you're asking it to print a null-terminated array of characters as a string.
The confusion here is that you're thinking of strings as a "native type" in the same way as integers and characters. C doesn't work that way; a string is just a pointer to a bunch of characters ending with a null byte.
If you really want to think of strings as a native type (keeping in mind that they really aren't), think of it this way: the type of a string is char *, not char. So, printf("%s\n", a); works because you're passing a char * to match with a format specifier indicating char *. To get the equivalent problems as with the second example, you'd need to pass a pointer to a string—that is, a char **.
Alternatively, the equivalent of %d is not %s, but %c, which prints a single character. To use it, you do have to pass it a character. printf("%c\n", a) will have the same problem as printf("%d\n", b).
From your comment:
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
This is where the loose thinking of strings as native objects falls down.
When you write this:
char *a = "abc";
What happens is that the compiler stores a array of four characters—'a', 'b', 'c', and '\0'—somewhere, and a points at the first one, the a. As long as you remember that "abc" is really an array of four separate characters, it makes sense to think of a as a pointer to that thing (at least if you understand how arrays and pointer arithmetic work in C). But if you forget that, if you think a is pointing at a single address that holds a single object "abc", it will confuse you.
Quoting from the GNU printf man page (because the C standard isn't linkable):
d, i
The int argument is converted to signed decimal notation …
c
… the int argument is converted to an unsigned char, and the resulting character is written…
s
… The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0') …
One last thing:
You may be wondering how printf("%s", a) or strchr(a, 'b') or any other function can print or search the string when there is no such value as "the string".
They're using a convention: they take a pointer to a character, and print or search every character from there up to the first null. For example, you could write a print_string function like this:
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
Or:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
Either way, you're assuming the char * is a pointer to the start of an array of characters, instead of just to a single character, and printing each character in the array until you hit a null character. That's the "null-terminated string" convention that's baked into functions like printf, strstr, etc. throughout the standard library.
Strings aren't really "first-class citizens" in C. In reality, they're just implemented as null-terminated arrays of characters, with some syntactic sugar thrown in to make programmers' lives easier. That means when passing strings around, you'll mostly be doing it via char * variables - that is, pointers to null-terminated arrays of char.
This practice holds for calling printf, too. The %s format is matched with a char * parameter to print the string - just as you've seen. You could use *a, but you'd want to match that with a %c or an integer format to print just the single character pointed to.
Your second example is wrong for a couple of reasons. First, it's not legal to make the assignment b = 1 without an explicit cast in C - you'd need b = (int *)1. Second, you're trying to print out a pointer, but you're using %d as a format string. That's wrong too - you should use %p like this: printf("%p\n", (void *)b);.
What it really looks like you're trying to do in the second example is:
int b = 1;
int *p = &b;
printf("%d\n", *p);
That is, make a pointer to an integer, then dereference it and print it out.
Editorial note: You should get a good beginner C book (search around here and I'm sure you'll find suggestions) and work through it.

Resources