snippet review please

A

alcastle

I'm new to C. I have a snippet of code that works, but it's a little
off in the output. I'm hoping someone can spot my error(s).

I'm reading input from a serial device, and I need to print Hex, which
is working but I'm getting unreliable output and have formating issues.

Example output:
FF00000033 FF00000036 FF00000030 FF00000030 FF00000054 FF0000001A
FF0000000F FF00000048 FF00000003 FF0000004A FF00000020 FF00000003
FF00000000 FF00000021 FF00000000 FF00000026 FF00000022 FF00000075
FF00000000 FF00000023 FF00000011 FF00000040 FF00000024 FF0000007F
FF00000040 FF00000025 FF0000000F FF00000050 FF00000026 FF0000007F
FF00000040 FF00000027 FF0000007F FF00000040 FF00000023

I can't figure out how to get rid of the FF000000 before the actual
HEX. And in about half of these the hex translation is wrong. Example:
the second to last frame on the last line; 40 should be C0.

I've tried various printf output options, but they all spit out
unreliable output with formating issues. I must be skipping a step, or
I need to multiply by something?

I've gone through the binary to hex posts and have tried some of the
things suggested but it's either over my head at this point or just
isn't working.

<snippet>
int res;
char buf[255];

retval = select(fd+1, &set, NULL,NULL, &timeout);

if (retval > 0) {
res = read(fd,buf,255);

if (res <= 0) {
printf("Error, res is <= 0");
}

int i;
buf[res]=0;

for (i=0;i<res;i++) {
printf("%0LX ", (int)(buf)); //mostly
}

</snippet>

Any suggestions would be greatly appreciated.
 
J

Jason

I'm new to C. I have a snippet of code that works, but it's a little
off in the output. I'm hoping someone can spot my error(s).

printf("%0LX ", (int)(buf)); //mostly


Would it make any difference if you cast to an unsigned int instead?
 
A

alcastle

Jason said:
printf("%0LX ", (int)(buf)); //mostly


Would it make any difference if you cast to an unsigned int instead?


Is this what you meant?

printf("%0LX ", (unsigned)(buf));

Or making i unsigned. I tried both, and the results are the same.
 
E

Eric Sosman

I'm new to C. I have a snippet of code that works, but it's a little
off in the output. I'm hoping someone can spot my error(s).

Interesting definition of "works" ...
I'm reading input from a serial device, and I need to print Hex, which
is working but I'm getting unreliable output and have formating issues.

Example output:
FF00000033 FF00000036 FF00000030 FF00000030 FF00000054 FF0000001A
[...]

Much of your code is not Standard C, and I won't
comment on it (besides, you didn't give enough context
to support much commentary). However, this line of
plain Standard C may be at least partially responsible:
printf("%0LX ", (int)(buf)); //mostly


The 'L' length modifier is wrong. In the first
place, it only applies to the 'a', 'A', 'e', 'E', 'f',
'F', 'g', and 'g' conversion specifiers; if it is used
with any other specifier "the behavior is undefined."
In the second place, the effect of 'L' (with a proper
conversion) is to say that the corresponding argument
is a `long double' instead of a `double' -- but you're
supplying an `int', which is neither.

On top of that, the `int' is wrong! The `X'
conversion requires an `unsigned int'.

Fix those two problems, and maybe your program will
stop "working."
 
O

Old Wolf

Eric said:
Example output:
FF00000033 FF00000036 FF00000030 FF00000030
[...]

Much of your code is not Standard C, and I won't
comment on it (besides, you didn't give enough context
to support much commentary). However, this line of
plain Standard C may be at least partially responsible:
printf("%0LX ", (int)(buf)); //mostly


The 'L' length modifier is wrong. In the first
place, it only applies to the 'a', 'A', 'e', 'E', 'f',
'F', 'g', and 'g' conversion specifiers; if it is used
with any other specifier "the behavior is undefined."


I've heard of systems that use L to indicate a 64-bit int.
Since the OP's example output has 10 hex digits (ie. is
more than 32-bit per number), this seems to be a reasonable
guess at what's going on.

Also, what does the 0 do when there isn't a width specifier
following it ?!

Secondly, some have suggested using (unsigned)buf .
Since buf is a char, if the char is negative then this
will result in a lot of F's, which the OP seems to be trying
to avoid. The correct usage would be:

printf("%X", (unsigned)(unsigned char)buf);

or perhaps "%08X". Another possibility would be to make
'buf' be unsigned char.
 
A

Alex Fraser

I'm new to C. I have a snippet of code that works, but it's a little
off in the output. I'm hoping someone can spot my error(s).

I'm reading input from a serial device, and I need to print Hex, which
is working but I'm getting unreliable output and have formating issues. [snip]
I've tried various printf output options, but they all spit out
unreliable output with formating issues. I must be skipping a step, or
I need to multiply by something? [snip]
char buf[255];

I guess your input is not signed; if so you should change this array to
unsigned char. Plain char may be signed or unsigned on a given
implementation - or selectable, eg via a command-line option.

[snip]
printf("%0LX ", (int)(buf)); //mostly


Assuming 8-bit bytes (and the change above), change this call to:
printf("%02X ", (unsigned)buf);

(I'm not sure the cast is actually strictly necessary.)

Alex
 
A

alcastle

It's a hodge podge from the Serial Programmers Howto and
the for(...) part is from a friend who's a C programmer.
Also, what does the 0 do when there isn't a width specifier
following it ?!

It just shows up as a single 0. Which is hard to read unless is
add a \n after each printf.
Secondly, some have suggested using (unsigned)buf .
Since buf is a char, if the char is negative then this
will result in a lot of F's, which the OP seems to be trying
to avoid. The correct usage would be:

printf("%X", (unsigned)(unsigned char)buf);


I tried this and the previously mentioned unsigned int.
The output is better in that there's no abundance of FF's, however the
translation still isn't consistant.

Here's output using the
printf("%X", (unsigned)(unsigned char)buf);

333630305417A648564A0780A17B99A2780A38FC0A4C0A5FD0A6C0A7C023
and again a second later.
333630305400480020750216C18227502380247F40251F60267F40277F4023
00 is now reading as 0, and the rest of the translation is incorrect.
For example the last part should read: A7FFC023
or perhaps "%08X".

This produces 0's in place of the FF's.

00000033000000360000003000000030000000540000001A00000004000000....
Another possibility would be to make
'buf' be unsigned char.

I tried that as well. I'm not sure my implementation is what you were
thinking of.

unsigned buf[255];
printf("%X", buf);

However now the problem is it's dropping valid FF's and NULL's show up
as 0 instead of 00, as well as sometimes C0 shows up as 40.

If I pad it with %0X I get too many FF's again.

This: A7FFFFC023 should actually read A7FFC023

I'm confused on where the problem lies.
 
A

alcastle

Alex said:
I guess your input is not signed; if so you should change this array to
unsigned char. Plain char may be signed or unsigned on a given
implementation - or selectable, eg via a command-line option.

Assuming 8-bit bytes (and the change above), change this call to:
printf("%02X ", (unsigned)buf);

(I'm not sure the cast is actually strictly necessary.)


So the revised code at this point.

unsigned char buf[255];
int res;

retval = select(fd+1, &set, NULL,NULL, &timeout);

if (retval > 0) {
res = read(fd,buf,255);

if (res <= 0) {
printf("Error, res is <= 0");
}

int i;
buf[res]=0;

for (i=0;i<res;i++) {
printf("%02X", (unsigned)buf);
}
}

Which outputs about as close as the others. Sometimes it's eating FF's
and also the conversion isn't consistant as mentioned before.

While we're speaking on unsigned/signed. Should int res be unsigned res?
 
M

Mark F. Haigh

I'm new to C. I have a snippet of code that works, but it's a little
off in the output. I'm hoping someone can spot my error(s).

I'm reading input from a serial device, and I need to print Hex, which
is working but I'm getting unreliable output and have formating
issues.

I've gone through the binary to hex posts and have tried some of the
things suggested but it's either over my head at this point or just
isn't working.

Any suggestions would be greatly appreciated.


You probably want something like this (although this is getting more
into UNIX / POSIX programming, which is off-topic here. Try
comp.unix.programmer down the hall):


void func(int fd, struct timeval *timeout)
{
int sret;
ssize_t rret, i;
unsigned char buf[256];
fd_set rfds;

FD_ZERO(&rfds);
FD_SET(fd, &rfds);

sret = select(fd + 1, &rfds, NULL, NULL, timeout);
if(sret < 0)
perror("select()");
else if(sret == 0)
printf("timeout\n");
else {
rret = read(fd, buf, sizeof buf);
if(rret < 0)
perror("read()");
else if(rret == 0)
printf("EOF\n");
else {
for(i = 0; i < rret; i++)
printf("%.02X%s", (unsigned int) buf,
(i + 1) % 16 ? " " : "\n");
printf("\n");
}
}
}

Not tested, but should work. Include the appropriate headers.



Mark F. Haigh
(e-mail address removed)
 
O

Old Wolf

Here's output using the
printf("%X", (unsigned)(unsigned char)buf);

333630305417A648564A0780A17B99A2780A38FC0A4C0A5FD0A6C0A7C023
and again a second later.
333630305400480020750216C18227502380247F40251F60267F40277F4023
00 is now reading as 0,
and the rest of the translation is incorrect.
For example the last part should read: A7FFC023


What 'translation' ? The code I suggested prints the bytes
as hex (no padding). If you aren't getting what you want, then your
bytes are wrong.
This produces 0's in place of the FF's.

It pads each byte to 8 hex digits.
00000033000000360000003000000030000000540000001A00000004000000....

Isn't that what you wanted?
unsigned buf[255];
printf("%X", buf);

However now the problem is it's dropping valid FF's and NULL's show up
as 0 instead of 00,


So you want padding to 2 hex digits? Then use "%02X"
as well as sometimes C0 shows up as 40.

If it shows up as 40 , then it was 40 in the buf[] array.
If you were expecting C0, then you have made a mistake
somewhere before you put the data into buf[].

If I pad it with %0X I get too many FF's again.

%0X is a MISTAKE !
You can only use '0' in the specifier if you follow it by how
many hex places you want to pad to, eg. %08X makes a total of
8 digits using 0 as the fill character.

(I'm pretty sure of that anyway; the reason I sounded vague
about it before is that the previous poster, Eric Sosman,
seemed to suggest it was not an error, and he knows lots about C)

If you get extra FF's then you are making a signed/unsigned error.
This: A7FFFFC023 should actually read A7FFC023

I'm confused on where the problem lies.

I'm confused on your requirements. Can you post a complete,
compilable program that displays the problem?
This works fine for me:

#include <stdio.h>

int main(void)
{
unsigned char buf[4] = { 0xA7, 0xFF, 0xC0, 0x23 };
int i;
for (i = 0; i != 4; ++i)
printf("%02X ", (unsigned)buf);
printf("\n");
return 0;
}

giving the output: A7 FF C0 23
 
A

alcastle

Old said:
I'm confused on your requirements. Can you post a complete,
compilable program that displays the problem?
This works fine for me:

Thanks to everyone who offered help. The solution was several fold.
This line:

char buf[255];

Needed to be

unsigned char buf[255];

And the for loop works as so:

for (i=0; i < res; i++) {
printf("%02X", buf);
}

What really clinched it was a serial option to "initialize control
characters", specifically '\0'.

options.c_cc[VE0L2] = 0;

Once I did that, the help provided was a complete success.

Thanks again to all.
 
D

Dave Thompson

On 19 May 2005 19:42:37 -0700, "Mark F. Haigh" <[email protected]>
wrote:

You probably want something like this (although this is getting more
into UNIX / POSIX programming, which is off-topic here. Try
comp.unix.programmer down the hall):


void func(int fd, struct timeval *timeout)

Concur with the (OT and snipped) Unix-I/O changes except that I might
not let select() clobber the caller's timeout variable when I'm taking
care of (and hiding) so much of the other stuff.
for(i = 0; i < rret; i++)
printf("%.02X%s", (unsigned int) buf,
(i + 1) % 16 ? " " : "\n");


%.02X is redundant, and thereby confusing to the competent reader:
%02X is one way of forcing 2 digits, and %.2X is another way.

Also if the compiler doesn't realize (i+1)%16 never involves negative
and hence can be optimized to a mask I'll make it 16U to help. Or just
use the more obvious nested loops (line, byte to 16 or whatever) since
my very slight inefficiency will be swamped by stdio anyway.
printf("\n");

This shouldn't be indented as if it were in the loop.


- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top