Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   print bits of unsigned value (http://www.velocityreviews.com/forums/t725642-print-bits-of-unsigned-value.html)

Mark 06-15-2010 11:08 AM

print bits of unsigned value
 
I need to print out a bits layout of 32-bit register, where bits 0-24
represent a network port's status (bit 1 is for up and 0 for down) and
others are not used. Simply printing each bit in a loop works fine, but I'd
like to write it in a buffer with formatted output, and this where I stuck:

puts("Group Ports");
puts(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
22 23 24");
puts("-----------------------------------------------------------------------------");

uint32_t val = 0x1234567; /* for this example */
char buf[66] = " "; /* 6 spaces */
int i, m = 0;

for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
/* 10 is left margin of spaces in the above string */
/* I have to smoothly move along the buffer to print 1 or 0
according to the port's number */

m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ? "1 " :
"0 "); /* XXX */
val = val << 1;
}
fprintf(stdout, "%s\n", buf);

This code is very clumsy and, in my understanding, XXX invokes underfined
behavior, because 'm' is used in two sequence points?
What would you recommend to improve/change to make it look clean and solid?

--
Mark


bart.c 06-15-2010 11:37 AM

Re: print bits of unsigned value
 

"Mark" <mark_cruzNOTFORSPAM@hotmail.com> wrote in message
news:hv7mvs$rcs$1@speranza.aioe.org...
>I need to print out a bits layout of 32-bit register, where bits 0-24
>represent a network port's status (bit 1 is for up and 0 for down) and
>others are not used. Simply printing each bit in a loop works fine, but I'd
>like to write it in a buffer with formatted output, and this where I stuck:
>
> puts("Group Ports");
> puts(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
> 22 23 24");
> puts("-----------------------------------------------------------------------------");
>
> uint32_t val = 0x1234567; /* for this example */
> char buf[66] = " "; /* 6 spaces */
> int i, m = 0;
>
> for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
> /* 10 is left margin of spaces in the above string */
> /* I have to smoothly move along the buffer to print 1 or 0
> according to the port's number */
>
> m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ? "1 "
> : "0 "); /* XXX */
> val = val << 1;
> }
> fprintf(stdout, "%s\n", buf);


Unless you are doing something else with 'buf', you might as well output the
bits immediately:

printf("%d ",val & 1); /* XXX */

--
Bartc


Ben Bacarisse 06-15-2010 11:43 AM

Re: print bits of unsigned value
 
"Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:

> I need to print out a bits layout of 32-bit register, where bits 0-24
> represent a network port's status (bit 1 is for up and 0 for down) and
> others are not used. Simply printing each bit in a loop works fine,
> but I'd like to write it in a buffer with formatted output, and this
> where I stuck:
>
> puts("Group Ports");
> puts(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> 20 21 22 23 24");
> puts("-----------------------------------------------------------------------------");
>
> uint32_t val = 0x1234567; /* for this example */
> char buf[66] = " "; /* 6 spaces */
> int i, m = 0;
>
> for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
> /* 10 is left margin of spaces in the above string */
> /* I have to smoothly move along the buffer to print 1 or 0
> according to the port's number */
>
> m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ?
> "1 " : "0 "); /* XXX */
> val = val << 1;
> }
> fprintf(stdout, "%s\n", buf);
>
> This code is very clumsy and, in my understanding, XXX invokes
> underfined behavior, because 'm' is used in two sequence points?
> What would you recommend to improve/change to make it look clean and
> solid?


(1) 66 is not enough space if the 0/1s are to line up under the numbers.
(2) You start with 6 spaces and then skip 10 places.
(3) val = val << 1; is not right. You probably mean val = val >> 1;
(4) The snprintf call is wrong: the space available is not sizeof(buf)
because you pass an ever increasing pointer to it.
(5) You seem to be putting the 0/1s into consecutive places (i.e. with
no space between them).
(6) The 0/1 won't line up under printed number unless you move on two
spaces for bit numbers > 9.
(7) Even if you fix number 2, you never null termiate the string that
you print in the last line.
(8) I'd write 1 rather than 0x00000001. They mean the same thing.
(9) You loop (and therefore write) at least 32 bits rather than 24.
(10) Why are you using a buffer rather than just printing the bits?

The biggest suggestion I have is not to use a buffer but that seems to
be built into your question for some reason. Why?

If I had to use a buffer, I'd:
(a) make it big enough (indent + 23 + 24 + 24 - 9 + 1) bytes;
(b) fill it with spaces and null terminate it;
(c) put the 0/1s into place using something like

buf[indent + i + (i > 9)] = val & 1 ? '1' : '0';

--
Ben.

ImpalerCore 06-15-2010 02:30 PM

Re: print bits of unsigned value
 
On Jun 15, 7:08*am, "Mark" <mark_cruzNOTFORS...@hotmail.com> wrote:
> I need to print out a bits layout of 32-bit register, where bits 0-24
> represent a network port's status (bit 1 is for up and 0 for down) and
> others are not used. Simply printing each bit in a loop works fine, but I'd
> like to write it in a buffer with formatted output, and this where I stuck:
>
> puts("Group * * Ports");
> puts(" * * * * * * * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
> 22 23 24");
> puts("-----------------------------------------------------------------------------");
>
> uint32_t val = 0x1234567; */* for this example */
> char buf[66] = " * * *"; */* 6 spaces */
> int i, m = 0;
>
> for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
> * * * * /* 10 is left margin of spaces in the above string */
> * * * * /* I have to smoothly move along the buffer to print 1 or 0
> according to the port's number */
>
> * * * * m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ? "1 " :
> "0 "); * /* XXX */
> * * * * val = val << 1;}
>
> fprintf(stdout, "%s\n", buf);
>
> This code is very clumsy and, in my understanding, XXX invokes underfined
> behavior, because 'm' is used in two sequence points?
> What would you recommend to improve/change to make it look clean and solid?


You can try my 'c_bit_snprintf' I posted back on Apr 1. It may not do
exactly what you want, but it's able to generate space separated
patterns of bits. There's no control flags to specify the amount of
spacing though It's limited to a single space, but it should be
trivial to change the spacing code EMIT_C( ' ' ) into what you need.

http://groups.google.com/group/comp....6b3800e12cfb62

Best regards,
John D.

bart.c 06-15-2010 03:34 PM

Re: print bits of unsigned value
 
"bart.c" <bartc@freeuk.com> wrote in message
news:pCJRn.53188$nW1.44746@hurricane...
>
> "Mark" <mark_cruzNOTFORSPAM@hotmail.com> wrote in message
> news:hv7mvs$rcs$1@speranza.aioe.org...
>>I need to print out a bits layout of 32-bit register, where bits 0-24
>>represent a network port's status (bit 1 is for up and 0 for down) and
>>others are not used. Simply printing each bit in a loop works fine, but
>>I'd like to write it in a buffer with formatted output, and this where I
>>stuck:

....

Since it doesn't appear you have tested your code, here is some ready-made
code that seems to work:

#include <stdio.h>

int main(void){
#define NBITS 24
int i;
int val=0x87654321;

printf ("Group Ports\n");
printf (" ");

for(i=1; i<=NBITS; ++i)
printf("%3d",i);

printf ("\n ");

for(i=1; i<=NBITS; ++i) {
printf("%3d",val&1);
val = val>>1;
}
printf("\n");

}

--
Bartc


Mark 06-16-2010 12:36 AM

Re: print bits of unsigned value
 

"Ben Bacarisse" <ben.usenet@bsb.me.uk> wrote in message
news:0.dc8db6880943d21eb7bc.20100615124336BST.87r5 k8h66v.fsf@bsb.me.uk...
[skip]
> The biggest suggestion I have is not to use a buffer but that seems to
> be built into your question for some reason. Why?
>
> If I had to use a buffer, I'd:
> (a) make it big enough (indent + 23 + 24 + 24 - 9 + 1) bytes;
> (b) fill it with spaces and null terminate it;
> (c) put the 0/1s into place using something like
>
> buf[indent + i + (i > 9)] = val & 1 ? '1' : '0';


I've thought it through and it appears to me now I don't need a buffer at
all, simple printf would do the job just fine.
Thanks, Ben & Bart.

--
Mark


Barry Schwarz 06-16-2010 04:11 AM

Re: print bits of unsigned value
 
On Tue, 15 Jun 2010 20:08:44 +0900, "Mark"
<mark_cruzNOTFORSPAM@hotmail.com> wrote:

>I need to print out a bits layout of 32-bit register, where bits 0-24
>represent a network port's status (bit 1 is for up and 0 for down) and
>others are not used. Simply printing each bit in a loop works fine, but I'd
>like to write it in a buffer with formatted output, and this where I stuck:
>
>puts("Group Ports");
>puts(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
>22 23 24");
>puts("-----------------------------------------------------------------------------");
>
>uint32_t val = 0x1234567; /* for this example */
>char buf[66] = " "; /* 6 spaces */
>int i, m = 0;
>
>for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
> /* 10 is left margin of spaces in the above string */
> /* I have to smoothly move along the buffer to print 1 or 0
>according to the port's number */
>
> m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ? "1 " :
>"0 "); /* XXX */
> val = val << 1;
>}
>fprintf(stdout, "%s\n", buf);
>
>This code is very clumsy and, in my understanding, XXX invokes underfined
>behavior, because 'm' is used in two sequence points?
>What would you recommend to improve/change to make it look clean and solid?


Dealing only with your concern for undefined behavior: There is no
restriction on the number of times an object is used between sequence
points. The restriction is on the number of times it is modified
between sequence points (max of 1).

Furthermore, there is a sequence point after the arguments to snprintf
are evaluated but before the function is called. There is also a
sequence point when the function returns.

If we consider
m += snprintf(...);
to be the same as
m = m + ... snprintf(...);
then it is clear that m is modified only once. So the question of
undefined behavior hinges on whether the value of m being evaluated is
being used to determine the new value.

If snprintf is called first and then m is evaluated, the sequence is
evaluated arguments (including m)
sequence point
call snprintf
sequence point
evaluate m
update m
sequence point for semicolon
Between the sequence points where m is updated, it is updated only
once and the evaluation is only to determine the new value.

If m is evaluated first and then snprintf is called, the sequence is
evaluate m
evaluate arguments (including evaluating m again)
sequence point
call snprintf
sequence point
update m
sequence point for semicolon
Obviously, between the sequence points where m is updated, it is
updated once and never evaluated.

It is possible for m and the arguments to be evaluated first, then
call snprintf, and then update m. In this case, once snprintf is
called, the sequence is the same as above.

Therefore, undefined behavior of the type you describe does not occur.

I'm also pretty sure
x = x + x*x - 1/x;
does not violate the intent of 6.5-2.

--
Remove del for email

David Thompson 07-02-2010 04:10 AM

Re: print bits of unsigned value
 
On Tue, 15 Jun 2010 12:43:36 +0100, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:

> "Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:
>
> > puts(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
> > 20 21 22 23 24");


> > uint32_t val = 0x1234567; /* for this example */
> > char buf[66] = " "; /* 6 spaces */
> > int i, m = 0;
> >
> > for (i = 0; i < sizeof(val) * CHAR_BIT; i++) {
> > /* 10 is left margin of spaces in the above string */
> > /* I have to smoothly move along the buffer to print 1 or 0
> > according to the port's number */
> >
> > m += snprintf(buf + 10 + m, sizeof(buf), (val & 0x00000001) ?
> > "1 " : "0 "); /* XXX */
> > val = val << 1;
> > }


> (1) 66 is not enough space if the 0/1s are to line up under the numbers.
> (2) You start with 6 spaces and then skip 10 places.


Yes, plus the label line shown is actually indented *14*.

> (3) val = val << 1; is not right. You probably mean val = val >> 1;
> (4) The snprintf call is wrong: the space available is not sizeof(buf)
> because you pass an ever increasing pointer to it.


Yes, plus you don't need snprintf at all for the logic shown, if you
make buf big enough as you need to anyway.

> (5) You seem to be putting the 0/1s into consecutive places (i.e. with
> no space between them).


No; look closely: he had "0<sp>" and "1<sp>". It's only one space not
two where needed (as you say next), but it is one.

> (6) The 0/1 won't line up under printed number unless you move on two
> spaces for bit numbers > 9.


Yes. Or use all two-char labels e.g. 01 02 03 ... 09 10 ....

> (7) Even if you fix number 2, you never null termiate the string that
> you print in the last line.


No; snprintf does null-terminate unless n is zero. Even if it
truncates. In this loop all but the last are then overwritten.

> (8) I'd write 1 rather than 0x00000001. They mean the same thing.
> (9) You loop (and therefore write) at least 32 bits rather than 24.


Yes.

> (10) Why are you using a buffer rather than just printing the bits?
>
> The biggest suggestion I have is not to use a buffer but that seems to
> be built into your question for some reason. Why?
>

Mu.

> If I had to use a buffer, I'd:
> (a) make it big enough (indent + 23 + 24 + 24 - 9 + 1) bytes;
> (b) fill it with spaces and null terminate it;
> (c) put the 0/1s into place using something like
>
> buf[indent + i + (i > 9)] = val & 1 ? '1' : '0';


More like buf [ indent + i*2 + (i>9)*(i-9) -1 ] .

But I consider this yucky and fragile; I've been bit too many times by
code that computes a place in the middle of some big and complicated
thing, and especially after maintenance elsewhere it *sometimes*
doesn't get quite the right place. Where it's cheap and simple enough
to build in sequence, which it is here, I would just allocate 24*3 +
slop and use the moving index (or pointer) like:
m = indent;
...
m += sprintf (buf+m, "%*c", i>9?3:2, (val&1)+'0');

or to be cleverer, probably unduly so:
static const char threecharvals [2] [4] = { " 0", " 1" };
...
m += strlen (strcpy (buf+m, threecharvals[val&1] + (i<=9) ) );

and maybe assert (m < sizeof buf) to catch maintenance screwup.

With the obvious adjustments if I went to all-3-wide per above.



All times are GMT. The time now is 03:11 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.