tags:

views:

184

answers:

6

I have a function which reads in a character, one byte at a time, through the serial port. After these bytes are collected, they are passed to a method to process the bytes and message.

I know how to fix the problem (fix is below), but why do my bytes get truncated when I don't perform the fix?

unsigned char dpBuf[255];
...

// Pretend dpBuf has values 0x01 0x02 0x03 0x00 0x00 0x00 0x04 0x05
..
ProcessMsg(dpBuf);
..
void ProcessMsg(unsigned char *buff)
{
    // buff comes in as 0x01 0x02 0x03 0x00 and rest is truncated
    char p[255];
    ...
    for (int i = 0; i < sizeof(buff); i++) 
    {
        sprintf(p, " 0x%X ", (unsigned char)b[i]);
    }
    ..
}

Fix:

ProcessMsg((unsigned char*)&dpBuf, length); // instead of sizeof() in the loop, use length

..

void ProcessMsg (unsigned char *buff, int length)
{
    // buff comes in as the original character string and is not truncated
    .. 
    // do for loop, print out contents

}
A: 

Your code is wrong: for (int i = 0; i < sizeof(buff); i++)

It's using sizeof which in fact equivalent to calling sizeof(unsigned char*). You have to pass the length explicitely.

Gregory Pakosz
Yes but why is it different when I pass by reference rather than by value?
0A0D
right but strlen truncates on the first \0 thinking it is the end of the string, but it sometimes is not due to how this particular protocol is written.. that's why I was using sizeof previously
0A0D
sizeof cannot tell you how many bytes of memory are allocated to a pointer, regardless of whether the pointer points to another variable, is the first address of an array, or is allocated with malloc on the heap. sizeof simply cannot do that. Using sizeof on a pointer will give you the size of the pointer, not the size of the pointed-to memory.
Tyler McHenry
@Tyler> I never pretended that. I just told (being off topic) that `sizeof("bla bla bla");` that is applying `sizeof` to a string literal is the only situation where the OP would get the string length
Gregory Pakosz
I was responding to Roboto's second comment, not your answer. Sorry.
Tyler McHenry
+12  A: 

buff is declared as const char*, so sizeof(buff) returns the size of such a pointer, which seems to be 4 bytes on your machine. Therefore the first four bytes of the buffer are then printed in the loop.

It doesn't matter that dpBuf is declared as an array of larger size because it is passed to the function as a pointer. To circumvent this problem you should add a parameter to the function where the size of the buffer is passed explicitly.

sth
Yes but when I go into debug and I inspect before it gets to the printing, there are only 4 bytes in that buffer.. regardless of sizeof()
0A0D
Whatever inspection tool you are using is probably assuming that the contents of a const char* are a C-string and so respecting the "C strings end with a \0 byte" rule to avoid showing characters after the end of the string, which would normally be junk.
Tyler McHenry
+1  A: 

sizeof( buff) is asking for the size of a pointer - probably 4

pm100
In debug, by inspection, the buffer is only holding four bytes.. it does not matter if it is six bytes before the first 0x00, it will always truncate without the fix
0A0D
+3  A: 

buff is a pointer and hence its size is 4. sizeof(buff) = 4 sizeof(dpBuf) = 255

You wanted the second one.

Sudhanshu
+1  A: 

Sizeof(buff) returns the size of a const char * because that is the type of buff. I think the method you were looking for is strlen(buff), but even then strlen will stop when it finds a null terminator. http://www.cplusplus.com/reference/clibrary/cstring/strlen/

In standard ascii 0x00 is considered a null terminator which is generally considered the end of a c style string.

I might suggest you look at using stl strings as well http://www.cplusplus.com/reference/string/string/

tamulj
Right.. I think now that the compiler was truncating that string by respecting the rule described by Tyler above. Tracking the length and sending it along with a reference to the original buffer works as desired
0A0D
+3  A: 

As everyone has said, in C++ a null-terminated char array is referred to as a string. The size of the buffer the chars are stored in can be larger then the "string length" in these terms. For example:

char inBuf [] = {0x01, 0x02, 0x03, 0x00, 0x00, 0x04, 0x05};
size_t bufSize = sizeof(inBuf);
size_t rawLen = strlen(inBuf);

...in this case the size of inBuf is 7, but strlen() returns 3.

Using ASCII you can't embed NULLs in a string. However, you can use the std::string if you want to embed NULLs. std::string is generally useful anyway, so check it out. Full working example:

#include <cstdlib>

#include <string>
#include <iostream>
using namespace std;

char inBuf [] = {0x01, 0x02, 0x03, 0x00, 0x00, 0x04, 0x05};

int main()
{
    size_t bufSize = sizeof(inBuf);
    size_t rawLen = strlen(inBuf);
    string ss(inBuf, sizeof(inBuf));
    size_t ssLen = ss.length();

    cout << "Buffer Size = " << bufSize << ", Raw string length = " << rawLen << ", std::string length = " << ssLen;

    return 0;

}

The program output is:

Buffer Size = 7, Raw string length = 3, std::string length = 7

John Dibling