Encoding strings and ints for a RPC - c

I need to do a RPC. I'm trying to encode the length of a function name followed by the name of the function.
Function name: say_hello
Function name length: 9
Encoded array: [9, 's', 'a', 'y', ..., 'l', 'l', 'o']
So far:
unsigned char* encode_int(unsigned char *buffer, int value) {
buffer[0] = value >> 24;
buffer[1] = value >> 16;
buffer[2] = value >> 8;
buffer[3] = value;
return buffer + 4;
}
char* function_name = "say_hello";
char* buffer[256];
buffer = encode_int(&buffer, strlen(function_name));
strcpy(buffer, function, strlen(function_name));
puts(buffer);

You have lots of problems with your code. I won't just give you a working solution but will point out the problems. The first thing is that the code obviously doesn't compile. You are passing an undefined variable function to strcpy and give too many arguments to strcpy. I'll assume you've just transcribed the program incorrectly. But even if you fix that you will get a few compiler warnings which, if heeded, would identify most of your problems.
You are passing the address of buffer rather than the buffer itself to encode_int.
You declare buffer as an array of char pointers. Looks like what you really want is an array of char.
You encode an int into the start of the buffer. And then you try to print it as a string (via puts). That's not going to work and will result in no output (as you have probably found). Because the int will have a 0 value in the first byte (as you have encoded it). This is a null terminator for a string and hence the blank output.
EDIT: Correction to point 3. You've actually incremented buffer by 4 (if everyting else was fixed). So the puts will only show the function name (again, if everything else was fixed). And you've effectively lost the function name length.

Put words into buffer like this
int len;
len=Strlen(word);
memcpy(buffer,&len,sizeof(Int));
strncpy (&buffer[sizeof (int)],word,len);
Change the puts line to read
printf("%d %s\n",buffer,&buffer[sizeof (int)]);

Related

Unexplainable behaviour when printing out strings in C

The following code works as expected and outputs ABC:
#include <stdio.h>
void printString (char toPrint [100]);
int main()
{
char hello [100];
hello[0] = 'A';
hello[1] = 'B';
hello[2] = 'C';
hello[3] = '\0';
printString(hello);
}
void printString (char toPrint [100])
{
int i = 0;
while (toPrint[i] != '\0')
{
printf("%c", toPrint[i]);
++i;
}
}
But if I remove the line that adds the null-character
hallo[3] = '\0';
I get random output like wBCÇL, ╗BCÄL, ┬BCNL etc.
Why is that so? What I expected is the loop in printString() to run forever because it doesn't run into a '\0', but what happend to 'A', 'B' and 'C'? Why do B and C still show up in the output but A is replaced by some random character?
You declaration of hello leaves it uninitialized and filled with random bytes
int main()
{
char hello [100];
...
}
If you want zero initialized array use
int main()
{
char hello [100] = {0};
...
}
There must have been, by pure chance, the value for \r somewhere in the memory cells following those of my array hello. That's why my character 'A' was overwritten.
On other machines, "ABC" was ouput as expected, followed by random characters.
Initializing the array with 0s, purposely omitted here, of course solves the problem.
edit:
I let the code print out each character in binary and toPrint[5] was indeed 00001101 which is ASCII for \r (carriage return).
When you declare an automatic like char hello [100];, the first thing to understand is that the 100 bytes can contain just about anything. You must assign values to each byte explicitly to do / have something meaningful.
You are terminating you loop when you find the \0 a.k.a the NUL character. Now, if you comment out the instruction which puts the \0 after the character c, your loop runs until you actually find \0.
Your array might contain \0 at some point or it might not. There are chances you might go beyond the 100 bytes still looking for a \0 and invoke undefined behaviour. You also invoke UB when you try to work with an unassigned piece of memory.

Why isn't my 8-bit pointer updating correctly?

Directions are here:
I'm supposed to convert the ASCII string in the exact same input buffer, which is in this case pt1.
Unfortunately for me, the loop is executed only once and hence my output buffer only contains the first short value.
I'm trying to convert the ASCII string into a Unicode 16-bit string. According to the directions, pt1 is supposed to point to an ASCII string.
Expected Output is on this link.
https://i.stack.imgur.com/COpXl.jpg
void Convert(unsigned short *pt1) {
// pt1 is a pointer to a null-terminated variable length ASCII string
// 0x30 0x31 0x32 0x00 (sentinel value)
unsigned char *pt2 = (unsigned char *)pt1;
unsigned char value = *pt2;
while (*pt2 != 0x00) {
value = *pt2;
*pt1 = (unsigned short)value;
pt2++;
pt1++;
}
*pt1 = 0x0000;
}
There are multiple problems:
Your conversion function does not produce anything visible for the caller: you store code point values into a local array and return to the caller. The compiler warns you that at least pt3 is set and not used, but a more advanced compiler would optimise away all code for this function without a side effect.
What is the API description for Convert? You seem to receive a pointer to an ASCII string disguised as a pointer to unsigned short, and it seems the conversion should be performed in place. If this is the actual requirement, it is a very bad idea. The function should receive a pointer to a destination array with type unsigned short *, a size_t specifying the number of elements of this array and a pointer to the source string, with type const char *.
How should bytes outside the ASCII range be handled? Is the source string encoded in a given code page? it is UTF-8 encoded? Should the function report an error?
From the EDIT, you seem to confirm the insane API requirement. Assuming there is enough space in the argument array, you should perform the conversion from the last byte to the first, thus avoiding stepping on your own toes:
void Convert(unsigned short *pt1) {
// pt1 is a pointer to a null-terminated variable length ASCII string
// with enough space to receive the converted value including a null terminator
unsigned char *pt2 = (unsigned char *)pt1;
size_t i;
// Compute the number of bytes
for (i = 0; pt2[i] != '\0'; i++)
continue;
// Convert the contents from right to left
// Assuming ISO8859-1 encoding for bytes outside the ASCII range
for (;;) {
pt1[i] = (unsigned short)pt2[i];
if (i-- == 0)
break;
}
}

Why is the entirety of this first array being added onto the second, on top of the two values (from the first) that I assign it?

I want to assign the first two values from the hash array to the salt array.
char hash[] = {"HAodcdZseTJTc"};
char salt[] = {hash[0], hash[1]};
printf("%s", salt);
However, when I attempt this, the first two values are assigned and then all thirteen values are also assigned to the salt array. So my output here is not:
HA
but instead:
HAHAodcdZseTJTC
salt is not null-terminated. Try:
char salt[] = {hash[0], hash[1], '\0'};
Since you are adding just two characters to the salt array and you are not adding the '\0' terminator.
Passing a non nul terminated array as a parameter to printf() with a "%s" specifier, causes undefined behavior, in your case it prints hash in my case
HA#
was printed.
Strings in c use a special convetion to know where they end, a non printable special character '\0' is appended at the end of a sequence of non-'\0' bytes, and that's how a c string is built.
For example, if you were to compute the length of a string you would do something like
size_t stringlength(const char *string)
{
size_t length;
for (length = 0 ; string[length] != '\0' ; ++length);
return length;
}
there are of course better ways of doing it, but I just want to illustrate what the significance of the terminating '\0' is.
Now that you know this, you should notice that
char string[] = {'A', 'B', 'C'};
is an array of char but it's not a string, for it to be a string, it needs a terminating '\0', so
char string[] = {'A', 'B', 'C', '\0'};
would actually be a string.
Notice that then, when you allocate space to store n characters, you need to allocate n + 1 bytes, to make room for the '\0'.
In the case of printf() it will try to consume all the bytes that the passed pointer points at, until one of them is '\0', there it would stop iterating through the bytes.
That also explains the Undefined Behavior thing, because clearly printf() would be reading out of bounds, and anything could happen, it depends on what is actually there at the memory address that does not belong the the passed data but is off bounds.
There are many functions in the standard library that expect strings, i.e. _sequences of non nul bytes, followed by a nul byte.

C Programming - Functionality of strlen

I'm working to try and understand some string functions so I can more effectively use them in later coding projects, so I set up the simple program below:
#include <stdio.h>
#include <string.h>
int main (void)
{
// Declare variables:
char test_string[5];
char test_string2[] = { 'G', 'O', '_', 'T', 'E', 'S', 'T'};
int init;
int length = 0;
int match;
// Initialize array:
for (init = 0; init < strlen(test_string); init++)
{ test_string[init] = '\0';
}
// Fill array:
test_string[0] = 'T';
test_string[1] = 'E';
test_string[2] = 'S';
test_string[3] = 'T';
// Get Length:
length = strlen(test_string);
// Get number of characters from string 1 in string 2:
match = strspn(test_string, test_string2);
printf("\nstrlen return = %d", length);
printf("\nstrspn return = %d\n\n", match);
return 0;
}
I expect to see a return of:
strlen return = 4
strspn return = 4
However, I see strlen return = 6 and strspn return = 4. From what I understand, char test_string[5] should allocate 5 bytes of memory and place hex 00 into the fifth byte. The for loop (which should not even be nessecary) should then set all the bytes of memory for test_string to hex 00. Then, the immediately proceeding lines should fill test_string bytes 1 through 4 (or test_string[0] through test_string[3]) with what I have specified. Calling strlen at this point should return a 4, because it should start at the address of string 0 and count an increment until it hits the first null character, which is at string[4]. Yet strlen returns 6. Can anyone explain this? Thanks!
char test_string[5];
test_string is an array of 5 uninitialized char objects.
for (init = 0; init < strlen(test_string); init++)
Kaboom. strlen scans for the first '\0' null character. Since the contents of test_string are garbage, the behavior is undefined. It might return a small value if there happens to be a null character, or a large value or program crash if there don't happen to be any zero bytes in test_string.
Even if that weren't the case, evaluating strlen() in the header of a for loop is inefficient. Each strlen() call has to re-scan the entire string (assuming you've given it a valid string), so if your loop worked it would be O(N2).
If you want test_string to contain just zero bytes, you can initialize it that way:
char test_string[5] = "";
or, since you initialize the first 4 bytes later:
char test_string[5] = "TEST";
or just:
char test_string[] = "TEST";
(The latter lets the compiler figure out that it needs 5 bytes.)
Going back to your declarations:
char test_string2[] = { 'G', 'O', '_', 'T', 'E', 'S', 'T'};
This causes test_string2 to be 7 bytes long, without a trailing '\0' character. That means that passing test_string2 to any function that expects a pointer to a string will cause undefined behavior. You probably want something like:
char test_string2[] = "GO_TEST";
strlen searches for '\0' character to count them, in your test_string, there is none so it continues until it finds one which happens to be 6 bytes away from the start of your array since it is uninitialized.
The compiler does not generate code to initialize the array so you don't have to pay to run that code if you fill it later.
To initialize it to 0 and skip the loop, you can use
char test_string[5] = {0};
This way, all character will be initialized to 0 and your strlen will work after you filled the array with "TEST".
There are a few problems here. First of all, char test_string[5]; simply sets aside 5 bytes for that string, but does not set the bytes to anything. In particular, when you say "char test_string[5] should allocate 5 bytes of memory and place hex 00 into the fifth byte", the second part is wrong.
Secondly, your array initialization loop uses strlen(test_string) but since the bytes of test_string are uninitialized, there's no way to know what's there so strlen(test_string) returns some undefined result. A better way to clear the array would be memset( test_string, 0, sizeof(test_string) );.
You fill the array with "TEST" but don't set the NULL byte at the end, so the last byte is still uninitialized. If you do the memset above this will be fixed, or you can manually do test_string[4] = '\0'.

C - casting int to char and append char to char

I am making my first parallel application, but I am stuck with basics of C. I need to know, how to cast int to char and then how to append one char to another.
It you could help me please, i would be glad. Thank you.
You can use itoa function to convert the integer to a string.
You can use strcat function to append characters in a string at the end of another string.
If you want to convert a integer to a character, just do the following -
int a = 65;
char c = (char) a;
Note that since characters are smaller in size than integer, this casting may cause a loss of data. It's better to declare the character variable as unsigned in this case (though you may still lose data).
To do a light reading about type conversion, go here.
If you are still having trouble, comment on this answer.
Edit
Go here for a more suitable example of joining characters.
Also some more useful link is given below -
http://www.cplusplus.com/reference/clibrary/cstring/strncat/
http://www.cplusplus.com/reference/clibrary/cstring/strcat/
Second Edit
char msg[200];
int msgLength;
char rankString[200];
........... // Your message has arrived
msgLength = strlen(msg);
itoa(rank, rankString, 10); // I have assumed rank is the integer variable containing the rank id
strncat( msg, rankString, (200 - msgLength) ); // msg now contains previous msg + id
// You may loose some portion of id if message length + id string length is greater than 200
Third Edit
Go to this link. Here you will find an implementation of itoa. Use that instead.
Casting int to char is done simply by assigning with the type in parenthesis:
int i = 65535;
char c = (char)i;
Note: I thought that you might be losing data (as in the example), because the type sizes are different.
Appending characters to characters cannot be done (unless you mean arithmetics, then it's simple operators). You need to use strings, AKA arrays of characters, and <string.h> functions like strcat or sprintf.
Casting int to char involves losing data and the compiler will probably warn you.
Extracting a particular byte from an int sounds more reasonable and can be done like this:
number & 0x000000ff; /* first byte */
(number & 0x0000ff00) >> 8; /* second byte */
(number & 0x00ff0000) >> 16; /* third byte */
(number & 0xff000000) >> 24; /* fourth byte */
int myInt = 65;
char myChar = (char)myInt; // myChar should now be the letter A
char[20] myString = {0}; // make an empty string.
myString[0] = myChar;
myString[1] = myChar; // Now myString is "AA"
This should all be found in any intro to C book, or by some basic online searching.
int i = 100;
char c = (char)i;
There is no way to append one char to another. But you can create an array of chars and use it.

Resources