1

I have this code:

int main(){

char buffer[1024];
char port = 1;
int length = 255;
char * record = "$TAG ,0 ,89 ,0, 1\n";

if(length < 0 || length > 255){
    printf("Error - length out of range for an unsigned char.\n");
    exit(1);
}

snprintf(buffer, 1024, "%c%c%s", port, (unsigned char) length, record);

int port_rc     = buffer[0];
int length_rc   = buffer[1]; 

printf("port_rc: %d\n",port_rc);
printf("length_rc: %d\n",length_rc);

return 0;

}

Output when I run it:

port_rc: 1 length_rc: -1

I think I am missing something here in terms of snprintf() as i'm not seeing the 255 value when reading the array it created back. My guess is that snprintf() is promoting the variable 'length' to an int or something. Does anyone know how I can achieve this?

Thanks.

Fra
  • 393
  • 7
  • 19
  • 6
    The first char of `"255"` is `'2'` which has the value `50` in ascii. – tkausl Jan 09 '19 at 21:56
  • 1
    @tkausl What keeps you from making an answer? – Yunnosch Jan 09 '19 at 22:00
  • 1
    Will you *ever* get `255` by using a different format specifier? The `char` is presumed signed, since you use an `(unsigned char)` cast rather than `(char)`. So you would get `-1`. – Weather Vane Jan 09 '19 at 22:09
  • `buffer[1]` has type `char`, it is literally impossible for it to store 255 (assuming your system has plain char as signed) – M.M Jan 10 '19 at 00:24
  • @M.M - yes that is why I was trying to use an usigned char. I've figured it out and you can see my solution in my answer. – Fra Jan 10 '19 at 15:22

3 Answers3

2

I don't think you can use sprintf() to store 255 into the buffer. The buffer argument to sprintf() is a char array. Whether char is signed or unsigned by default is implementation-defined; see Is char signed or unsigned by default?. If 255 is greater than CHAR_MAX, trying to store 255 results in undefined behavior; if the implementation defaults to signed then CHAR_MAX will probably be 127.

I suggest not using sprintf() to store numbers into the buffer. Declare it as:

unsigned char buffer[127];

Then you can do:

buffer[0] = port;
buffer[1] = length;
snprintf((char *)(buffer + 2), sizeof buffer - 2, "%s", record);
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Right, but doing that does not return 255 in the variable 'length_rc'. Please see modified code above. And if I change 'length' to 127 (largest signed character number) output is produced as expected. – Fra Jan 09 '19 at 23:00
  • 1
    I see the problem. The buffer is `char[]`, not `unsigned char[]`. So `buffer[1]` is signed. Storing `255` into the buffer results in undefined behavior. – Barmar Jan 09 '19 at 23:10
  • 1
    I've updated the answer to show how you can do this more safely. – Barmar Jan 09 '19 at 23:17
  • Thanks a ton @Bamar - i've incorporated your solution. My post is updated to reflect the working changes. – Fra Jan 10 '19 at 04:56
  • 1
    You should put the working solution in an answer, not the question. – Barmar Jan 10 '19 at 06:38
  • Done. Thanks again. – Fra Jan 10 '19 at 15:24
1

"Be careful, though," when judging such a "solution."

In my humble, the root problem – in your original post - is that the variables port_rc and length_rc should have been declared as unsigned integers. You do not want a value such as $FF to be erroneously "sign-extended" to become $FFFFFFFF == -1 ...

Your "solution" is quite different from the original because, as you see, it now stores into both buffer[0] and buffer[1] before then retrieving and examining those values!

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
0

WORKING SOLUTION:

int main(){

unsigned char buffer[1024];
char port = 1;
int length = 255;
char * record = "$TAG ,0 ,89 ,0, 1\n";

if(length < 0 || length > 255){
    printf("Error - length out of range for an unsigned char.\n");
    exit(1);
}

buffer[0] = port;
buffer[1] = length;
snprintf((char *)(buffer), sizeof buffer - 2, "%c%c%s", port,length,record);

int port_rc     = buffer[0];
int length_rc   = buffer[1]; 
char char_first = buffer[2];

printf("port_rc: %d\n",port_rc);
printf("length_rc: %d\n",length_rc);
printf("char_first: %c\n",char_first);


return 0;

}

RETURNS:

port_rc: 1 length_rc: 255 char_first: $

Fra
  • 393
  • 7
  • 19