-1

i use sscanf in this code

while(totalByte < sizeof(rdata)) 
{   
    read(client_sockfd, &buffer[totalByte],1); 
    printf("bytes[%d] : %x \n", totalByte, buffer[++totalByte]);
}

use this code and i got a result like this

client send 1 1 +

bytes[0] : 0  
bytes[1] : 0  
bytes[2] : 0  
bytes[3] : 1  
bytes[4] : 0  
bytes[5] : 0
bytes[6] : 0  
bytes[7] : 1  
bytes[8] : 2b 
bytes[9] : 0  
bytes[10] : 0  
bytes[11] : 0 
bytes[12] : 0  
bytes[13] : 0  
bytes[14] : 0  
bytes[15] : 0  
bytes[16] : 0  
bytes[17] : 0 
bytes[18] : 0  
bytes[19] : 0 

got a result

then i use sscanf method

sscanf(buffer,"%d%d%c" ,&rdata.left_num, &rdata.right_num, rdata.op); 
printf("%d %c %d \n", ntohl(rdata.left_num),rdata.op,ntohl(rdata.right_num));

but when print rdata(structure)'s value , get a 0 value(init value).

0 0

i know sscanf method split a string and insert a value

Is there a any misunderstood for me?

this is what i used structure

struct cal_data 
{  
    int left_num;  
    int right_num;
    char op;  
    int result;  
    int error;  
}; 
user207421
  • 305,947
  • 44
  • 307
  • 483
  • There are a number of things wrong with this, not even related to `sscanf()` (which I'm sure the answers below will cover in-spades). Ex: Which "byte" do you think is printed by your first loop going into any iteration of your choice. Specifically, `printf("bytes[%d] : %x \n", totalByte, buffer[++totalByte]);` Do you think this is dumping the byte at `buffer[totalByte]` ? Wanna bet on that? – WhozCraig Apr 06 '13 at 02:12
  • @WhozCraig because of writing rule i chance buffer[totalByte]; ++totalByte; to buffer[++totalByte]; – Kyeong Wook Ma Apr 06 '13 at 02:36
  • It is undefined behavior. The increment should be *outside* the `printf()` call unless it is the *only* occurrence of `totalByte` within the parameter list (which it is not). You had it right the first time. The increment belongs outside the parameter list as-written. – WhozCraig Apr 06 '13 at 02:39

3 Answers3

3

I don't think this is doing what you want it to:

printf("bytes[%d] : %x \n",totalByte, buffer[++totalByte]);

If that is working, then it's working by coincidence. You don't want to rely on coincidence, rather than logic, do you? Read this question for more information on the undefined behaviour here. Change it to this, and avoid omitting sequence points in order to cram logic together in the future:

printf("bytes[%d] : %x \n",totalByte, (unsigned int) buffer[totalByte]);
totalByte++;

then i use sscanf method sscanf(buffer,"%d%d%c" ,&rdata.left_num, &rdata.right_num, rdata.op);

Where is your error checking? Like most standard C functions, your code should be checking the return value of sscanf to ensure that it extracted the amount of information you want. How can you be sure sscanf successfully processed two decimal digit sequences and a character? Use this:

int n = sscanf(buffer,"%d%d%c" ,&rdata.left_num, &rdata.right_num, rdata.op);
if (n == 3) {
    /* sscanf extracted and assigned three values;
     * One for each of the format specifiers,
     * and variables you passed in. Success! */
    printf("%d %c %d \n", ntohl(rdata.left_num),rdata.op,ntohl(rdata.right_num));
}
else {
    /* sscanf failed to extract some values from the string,
     * because the string wasn't correctly formatted */
    puts("Invalid input to sscanf");
}

... and now you'll see the problem! sscanf failed!

As others have indicated, a string terminates at the first '\0' (or 0) byte. The pointer you're passing to sscanf points to an empty string. sscanf can't extract any of the information you want from an empty string.

Community
  • 1
  • 1
autistic
  • 1
  • 3
  • 35
  • 80
  • +1. The answer is sound, but the extra mile to hunt down and link the sequence pointer answer will ultimately be helpful to anyone that reads this if they want to understand better why that code is incorrect. – WhozCraig Apr 06 '13 at 02:40
2

sscanf like many other C library functions stops iterating a string when it reaches a 0 (same as '\0'). The first element of your bytes array is 0. Hence as far as sscanf is concerned, your input string used for sscanf is "". To see another example of this behaviour, add the following code after your while loop.

printf("%s\n", bytes);

This will not print anything (will print an empty string), because printf like sscanf will consider byte[0] to be the end of the string.

You should probably use something like this to read data into your structure - http://c-faq.com/stdio/extconform.html

user93353
  • 13,733
  • 8
  • 60
  • 122
  • 0 is not '\0'. 0 is in ASCII 48(dec.) – Koushik Shetty Apr 06 '13 at 02:12
  • @Koushik zero (`0x00`) or `0` printed as a decimal is what he's talking about, and he's right. Where in the code, or in this answer,, do you see any reference to the *character* `'0'` (which is the ASCII #48 you're referring to)? – WhozCraig Apr 06 '13 at 02:15
  • 1
    @Koushik - '0' is 48 in ascii. '\0' is 0. Try this - `printf("%d\n", '\0');` – user93353 Apr 06 '13 at 02:16
  • @WhozCraig he is printing in decimal format. which is output to the stdout in text format. so 0 converted to ascii for printing on the stdout. when we read the same we are essentially reading the acsii value formated to decimal value. isnt it? – Koushik Shetty Apr 06 '13 at 02:25
  • @Koushik It is dumped to stdout as an ASCII char after conversion in `printf()`. It is precisely that it is NOT an ASCII `'0'` in the input buffer used by `sscanf()` that is fails, which is the point of this answer (and is the reason it is correct). The buffer appears to `sscanf()` as if it is an empty string because the first byte presented to the data parser is 0x00 (i.e. a null-terminator). I hope that is clear. – WhozCraig Apr 06 '13 at 02:33
  • @WhozCraig now my error is clear to me. thanks for correcting. – Koushik Shetty Apr 06 '13 at 02:35
  • @WhozCraig oh i'm beating myself for this. i completely missed out 1 thing. We are sscanf'ing from the the `buffer` which should have been my first clue. sorry for the trouble. – Koushik Shetty Apr 06 '13 at 02:49
  • @Koushik - What else can you `sscanf` from? – user93353 Apr 06 '13 at 02:50
  • @user93353 i was in a totally different direction of `reading` from `stdout`:-). oh how stupid of me.even then its the same.wow – Koushik Shetty Apr 06 '13 at 02:59
1

According to function description (http://www.cplusplus.com/reference/cstdio/sscanf/):

int sscanf ( const char * s, const char * format, ...);

The first argument should be:

C string that the function processes as its source to retrieve the data.

But as you print out each byte as "hexadecimal integer":

printf("bytes[%d] : %x \n", totalByte, buffer[++totalByte]);

The value of the first byte is 0. So if you treat it as a string, it is an empty string.

Sheng
  • 3,467
  • 1
  • 17
  • 21
  • It definitely depands on protocals. Otherwise, which part do you think is not portable? – Sheng Apr 06 '13 at 02:38
  • What about alignment and [bus errors](http://en.wikipedia.org/wiki/Segmentation_fault#Bus_error_example)? – autistic Apr 06 '13 at 02:41
  • @Sheng *none* of it is portable. Even assuming you tackled the padding and packing issues, you still have potential endian issues. These are all the primary reasons you *don't send data structures across the wire.* You develop a data protocol make it portable, and generate well-defined byte-stream. – WhozCraig Apr 06 '13 at 02:43
  • Additionally, please don't use C++ websites as C references, particularly *that* C++ website. Consider googling "[opengroup sscanf](http://www.opengroup.org/susv3xsh/scanf.html)" for a comprehensive manual that's relevant to C. – autistic Apr 06 '13 at 02:46
  • @Sheng - I think padding details are not standardized. Though your code would probably work on a lot of platforms. – user93353 Apr 06 '13 at 02:49
  • @WhozCraig Yes, these issues exist. Thank your for your comments! Your practice is better. – Sheng Apr 06 '13 at 02:52
  • @modifiablelvalue Your choice is better. But even though this website is C++ website, the content is under the part of "C library". – Sheng Apr 06 '13 at 02:55
  • @user93353 Padding is compiler specified. But since what we deal with is the final data as shown. Actually, I did not care about the padding and alignment issue. What I received is what I deal with. The real issue the the endian. – Sheng Apr 06 '13 at 02:59