make a program using C,C++

D

David Bolt

I might be going mad (and people will correct me if I am wrong) but
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is usenet. You'll be corrected even if when you're not wrong.
isn't the following all true?
A numeric constant 1 in the source code as above will be treated as
being of type int

If you left shift 1 by the number of bits in an int you get a number
too big to be represented in an int thus causing an overflow

If you cause an overflow you are invoking undefined behaviour and
*anything* can happen. One likely result in the above being
initialising counter to 0, but stranger things could happen.

But, if you look again, you'll see that 1 isn't being left-shifted by
the number of bits in an int:

for(
counter=(sizeof(int)*8);
counter>=0;
--counter
)

While counter is initialised as the number of bits in an int, I
specifically used --counter to pre-decrement it before passing through
the loop. In other words, it starts with 1 being left-shifted by one
less than the number of bits in an int.


Regards,
David Bolt
 
P

pete

David Bolt wrote:
for(
counter=(sizeof(int)*8);
counter>=0;
--counter
)

While counter is initialised as the number of bits in an int, I
specifically used --counter to pre-decrement it before passing through
the loop. In other words, it starts with 1 being left-shifted by one
less than the number of bits in an int.

That's not how a for loop works.
Predecrement or postdecrement,
makes no difference in that case.

/* BEGIN new.c */

#include <stdio.h>

int main(void)
{
int x;

for (x = 1; x > 0; --x) {
printf("%d\n", x);
}
for (x = 1; x > 0; x--) {
printf("%d\n", x);
}
return 0;
}

/* END new.c */
 
D

David Bolt

for(
counter=(sizeof(int)*8);
counter>=0;
--counter
)

While counter is initialised as the number of bits in an int, I
specifically used --counter to pre-decrement it before passing through
the loop. In other words, it starts with 1 being left-shifted by one
less than the number of bits in an int.

That's not how a for loop works.
Predecrement or postdecrement,
makes no difference in that case.[/QUOTE]

<Snippety of example showing my misconception>

So, after showing off my lack of knowledge, it looks like I've finally
managed to learn something new today. I'd always thought that both a
pre-decrement and pre-increment meant that either the decrement, or
increment, took place before each run through the loop, not afterwards.

In other words, what I should have used is:

for(counter=(sizeof(int)*CHAR_BIT)-1;counter>=0;counter--)


Regards,
David Bolt
 
F

Flash Gordon

David said:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is usenet. You'll be corrected even if when you're not wrong.

True, as you proceed to demonstrate :)
But, if you look again, you'll see that 1 isn't being left-shifted by
the number of bits in an int:

for(
counter=(sizeof(int)*8);
counter>=0;
--counter
)

While counter is initialised as the number of bits in an int, I
specifically used --counter to pre-decrement it before passing through
the loop. In other words, it starts with 1 being left-shifted by one
less than the number of bits in an int.

The code snipped in full, with added commentary by me was
printf("\nBinary: ");
for(counter=(sizeof(int)*8);counter>=0;--counter)
{
/* First time though counter will be (sizeof(int)*8) since the --counter
expression is not executed until *after* the first execution of the loop */
temp = 1 << (counter);

/* So the above statement invokes undefined behaviour */

printf("%d", (number & temp) ? 1 : 0);
}

<aside>
I seem to remember a recent thread here about the merits of pre/post
increment when used like this and someone suggesting the pre-increment
could be miss-interpreted in exactly the way David Bolt has just done.
David has just proved that hypothesis, although I would personally use
that as an argument for David to learn more rather than to avoid the
pre-increment. I prefer the post increment, but as a matter of style
rather than belief that it is in some manner better.
</aside>

By the way, even if you "correct" it to:
printf("\nBinary: ");
for(counter=(sizeof(int)*8)-1;counter>=0;--counter)
{
temp = 1 << (counter);
printf("%d", (number & temp) ? 1 : 0);
}
You can still invoke undefined behaviour. To quote from N1124 section
6.5.7 para 4:
| The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated
| bits are filled with zeros. If E1 has an unsigned type, the value of
| the result is E1 * 2**E2, reduced modulo one more than the maximum
| value representable in the result type. If E1 has a signed type and
| nonnegative value, and E1 × 2**E2 is representable in the result type,
| then that is the resulting value; otherwise, the behavior is
| undefined.

I've used ** to represent "raising to the power" since superscript is
not easy to do.

Read the last sentence and you will see that trying to shift a 1 in to
the sign bit of a signed number (and 1 is a signed int) is explicitly
undefined behaviour.

Generally you should make sure you are using unsigned types when using
bit operators to avoid this kind of trap, and that includes specifying
constants as unsigned.
 
K

Keith Thompson

Flash Gordon said:
Google is just one of a vast number of interfaces to Google, and it is
a comparatively recent one at that.

I think you mean "Google is just one of a vast number of interfaces to
Usenet".

[...]
Whether it is easier to write like that is largely irrelevant. Please
understand that it is harder to read especially for people for whom
reading English is not easy or natural, such as Dyslexics and people
for whom English is not their first language. I know we have people in
both groups here. Also please remember, you write the post once but it
gets read many times, so if you spend an extra 30 seconds but save 20
people 5 seconds each it is *still* a net saving.

It's no fun for those of us who *do* have English as our first
language.
 
F

Flash Gordon

Keith said:
I think you mean "Google is just one of a vast number of interfaces to
Usenet".

You, you are quite correct. Can I use dyslexia as an excuse for using
the wrong word?
[...]
Whether it is easier to write like that is largely irrelevant. Please
understand that it is harder to read especially for people for whom
reading English is not easy or natural, such as Dyslexics and people
for whom English is not their first language. I know we have people in
both groups here. Also please remember, you write the post once but it
gets read many times, so if you spend an extra 30 seconds but save 20
people 5 seconds each it is *still* a net saving.

It's no fun for those of us who *do* have English as our first
language.

Agreed. I suspect it is worse for non-native English speakers, and I
know it makes it far harder for me as a dyslexic.

Thank dog for split chickens.
 
D

David Bolt

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is usenet. You'll be corrected even if when you're not wrong.

True, as you proceed to demonstrate :)[/QUOTE]

True :-(

The code snipped in full, with added commentary by me was
printf("\nBinary: ");
for(counter=(sizeof(int)*8);counter>=0;--counter)
{
/* First time though counter will be (sizeof(int)*8) since the --
counter expression is not executed until *after* the first execution of
the loop */

And that was my mistake. My (lack of) understanding was that the pre-
meant that the increment/decrement was performed before going through
the loop, not afterwards. Now I know I was wrong, and so publicly wrong
as well, it's fairly certain that I won't be repeating that error again.
temp = 1 << (counter);

/* So the above statement invokes undefined behaviour */

printf("%d", (number & temp) ? 1 : 0);

At least I got this bit (almost) right. Having thought about it, and I'm
probably going to see if I can fit a second foot in my mouth at the same
time, I think it would be better if temp was had an unsigned int type,
and after a couple of other tweaks, this code should be okay:

/* number.c */

#include <stdio.h>

int main()
{
int number = 0;
unsigned int temp = 0;
int counter;

printf("Give me a number: ");
scanf("%d", &number);
/*
ought to be checking here on the returned value just in case of
errors/overflows
*/

for(counter=(sizeof(int)*8)-1;counter>=0;counter--)
{
temp = 1UL << counter;
printf("%d", ((unsigned int)number & temp) ? 1 : 0);
}

printf("\n");

return 0;
}

/* number.c */

Now, knowing my luck, there's probably still something wrong. However,
GCC doesn't throw any warnings at me when it compiles, and it does give
the correct output for multiple test values.
}

<aside>
I seem to remember a recent thread here about the merits of pre/post
increment when used like this and someone suggesting the pre-increment
could be miss-interpreted in exactly the way David Bolt has just done.

At least I can still manage to be a good example of how a little
knowledge can be a dangerous thing.
David has just proved that hypothesis, although I would personally use
that as an argument for David to learn more rather than to avoid the
pre-increment.

Learning more does appear to be among the things I've been doing today.
I prefer the post increment, but as a matter of style rather than
belief that it is in some manner better.

After learning that in a for() post- and pre- apparently do the same
thing, it doesn't appear to matter which is used. Personally, I also use
post increments/decrements, but in this case was tripped up by my
misunderstanding.

Read the last sentence and you will see that trying to shift a 1 in to
the sign bit of a signed number (and 1 is a signed int) is explicitly
undefined behaviour.

Generally you should make sure you are using unsigned types when using
bit operators to avoid this kind of trap, and that includes specifying
constants as unsigned.

And there's another thing I've learnt today. All I have to do now is
remember to change my socks before I go sticking my feet in my mouth
again.


Regards,
David Bolt
 
P

pete

[/QUOTE]
And that was my mistake. My (lack of) understanding was that the pre-
meant that the increment/decrement was performed before going through
the loop, not afterwards. Now I know I was wrong,
and so publicly wrong
as well, it's fairly certain that I won't be repeating
that error again.


At least I got this bit (almost) right. Having thought about it,
and I'm
probably going to see if I can fit a second foot
in my mouth at the same
time, I think it would be better if temp was had an unsigned int type,
and after a couple of other tweaks, this code should be okay:

/* number.c */

#include <stdio.h>

int main()
{
int number = 0;
unsigned int temp = 0;
int counter;

printf("Give me a number: ");
scanf("%d", &number);
/*
ought to be checking here on the returned value just in case of
errors/overflows
*/

for(counter=(sizeof(int)*8)-1;counter>=0;counter--)
{
temp = 1UL << counter;
printf("%d", ((unsigned int)number & temp) ? 1 : 0);
}

printf("\n");

return 0;
}

/* number.c */

Now, knowing my luck, there's probably still something wrong. However,
GCC doesn't throw any warnings at me when it compiles,
and it does give
the correct output for multiple test values.

The (unsigned int) cast doesn't do anything,
because the & operator with the other unsigned operand,
already converts number to type unsigned.
number should probably be unsigned to begin with.
Bitwise operations on negative values are tricky.

CHAR_BIT is preferable to 8, for the number of bits in a byte.

There's also the matter of padding bits.
C99 allows that there may be unused bits in a byte,
that is to say that an int with a 16 bit range,
could be an object that has more than 16 bits.

For an unsigned integer type,
an unsigned expression that has only the most significant bit set
could be: (((unsigned)-1 >> 1) + 1)
 
M

Mark McIntyre

I think you mean "Google is just one of a vast number of interfaces to
Usenet".

I think the first version was better though... after all, Google is
widely considered to be so far up its own a&%^$NO CARRIER

Mark McIntyre
 
M

Malcolm

mavic said:
hi to everybody,i need help for my project....how to make a program
that accept any integer and convert it binary,octal and hexadecimal.pls
help me...thanks
Any integer?

Including 10^(10^10) ?
 
C

Chuck F.

David said:
.... snip ...

While counter is initialised as the number of bits in an int, I
specifically used --counter to pre-decrement it before passing
through the loop. In other words, it starts with 1 being
left-shifted by one less than the number of bits in an int.

Which shifts it into the sign bit and creates an overflow and
undefined behaviour. Use unsigned ints for that purpose.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
R

Richard Heathfield

Anup Bishnoi said:
here is a program my friend navjot made to convert decimal system
integer to binary.

u can easily change this program to show octal or hexadecimal or any
other system.

#include<stdio.h>
#include<math.h>
main()
{
int i,x,t,answer=0;
int num[15];

clrscr();

Hmmm. I don't see the point of that.
printf("Enter the digits of the binary number \n(pressing Enter
between 2 digits and enter 9 when finished entering) : \n");

for(i=0;i<15;i++)
{
scanf("%d",&num);


Forgive me, but I don't quite see how you are protecting against your user
typing ONE ONE ONE ZERO ZERO ONE ONE ONE ZERO ONE as input.
 
F

Flash Gordon

[/QUOTE]

At least I got this bit (almost) right. Having thought about it, and I'm
probably going to see if I can fit a second foot in my mouth at the same
time,

Indubitably ;-)
> I think it would be better if temp was had an unsigned int type,

Definite improvement, since the conversion of unsigned int to signed int
has a problem if the value is too large to fit in the signed int. so
you've side stepped that one nicely :)
and after a couple of other tweaks, this code should be okay:

/* number.c */

#include <stdio.h>

int main()
{
int number = 0;
unsigned int temp = 0;
int counter;

printf("Give me a number: ");
scanf("%d", &number);
/*
ought to be checking here on the returned value just in case of
errors/overflows
*/

for(counter=(sizeof(int)*8)-1;counter>=0;counter--)
{
temp = 1UL << counter;
printf("%d", ((unsigned int)number & temp) ? 1 : 0);
}

printf("\n");

return 0;
}

/* number.c */

Now, knowing my luck, there's probably still something wrong. However,
GCC doesn't throw any warnings at me when it compiles, and it does give
the correct output for multiple test values.

Well, there is just one little thing that I can see...
When number is converted to unsigned and number is negative, the
conversion will be done as if UINT_MAX to the value. On a 2's complement
machine (i.e. almost all machines these days) this will just reinterpret
the bits as unsigned. However, on a 1's complement or sign & magnitude
system (which the C standard still allows) it will change the bit
pattern. So, basically, your routine always prints the bit pattern of
the 2's complement representation of the number even if that is not what
the implementation uses.

Personally, for all of my real work (as opposed to picking nits here) I
would not worry about it.

At least I can still manage to be a good example of how a little
knowledge can be a dangerous thing.

Don't worry about it. We all make errors here.

Learning more does appear to be among the things I've been doing today.

With that attitude, I think you will do well in this group. So I'll let
you in to a trade secret...

You can legally download copies of the drafts of the various version of
the C standard for free. This page has the appropriate links
http://clc-wiki.net/wiki/Basics_Of_The_C_Standard
OK, so it's not really a secret. However, it is reference material you
might find useful.
After learning that in a for() post- and pre- apparently do the same
thing, it doesn't appear to matter which is used.

It does matter if you use the value of the expression, i.e. these two
are different:
for (i=0; i<10; j=i++) {
/* j uninitialised fist time round then 1 less than i
on subsequent iterations */
}

for (i=0; i<10; j=++i) {
/* j uninitialised fist time round then the same as i
on subsequent iterations */
}

And there's another thing I've learnt today. All I have to do now is
remember to change my socks before I go sticking my feet in my mouth
again.

This is good. Making honest errors on this group is fine, accepting
corrections is and learning from them is excellent.

Just don't take my word as gospel until you've either verified it or at
least seen that no one else is pointing out that I've got it wrong.
 
L

Logan Shaw

Sure, that's just 10.

It certainly could be, since the OP didn't specify what base the
input should be in, and you didn't specify what base the number
you gave was in.

Which brings up a point: should the OP's program accept numbers
in decimal only? What about negative numbers?

- Logan
 
K

Keith Thompson

Logan Shaw said:
It certainly could be, since the OP didn't specify what base the
input should be in, and you didn't specify what base the number
you gave was in.

I assumed 10 was a decimal literal and "^" was the standard bitwise
xor operator. (Yes, I was being deliberately silly.)
Which brings up a point: should the OP's program accept numbers
in decimal only? What about negative numbers?

That needs to be part of the specification.
 
A

August Karlstrom

mavic said:
hi to everybody,i need help for my project....how to make a program
that accept any integer and convert it binary,octal and hexadecimal.pls
help me...thanks

Here is my version (for the general case):

#include <assert.h>

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num, power = 1, k = 0, digit;

assert((base >= 2) && (base < 10 + 'Z' - 'A'));
while (rem / (power * base) > 0) { power *= base; }
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}


August
 
K

Keith Thompson

August Karlstrom said:
mavic said:
hi to everybody,i need help for my project....how to make a program
that accept any integer and convert it binary,octal and hexadecimal.pls
help me...thanks

Here is my version (for the general case):

#include <assert.h>

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num, power = 1, k = 0, digit;

assert((base >= 2) && (base < 10 + 'Z' - 'A'));
while (rem / (power * base) > 0) { power *= base; }
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}

I see at least two significant flaws. If they were unintentional,
I'll point them out; if they're deliberate (because it's probably a
homework problem), they're likely to get past the instructor.
 
P

Peter Nilsson

pete said:
...
void itoa_b(int n, char *s)
{
int half, min_offset;
char *p, swap;

min_offset = 0;
if (0 > n) {
if (-INT_MAX > n) {
++n;
++min_offset;
}

On my system, -2147483648 (INT_MIN) produced
-1111111111111111111111111111112.
n = -n;
*s++ = '-';
}
p = s;
half = n;
do {
half /= 2;
*p++ = (char)(n - 2 * half + '0');
n = half;
} while (half != 0);
*s = (char)(*s + min_offset);
*p-- = '\0';
while (p > s) {
swap = *s;
*s++ = *p;
*p-- = swap;
}
}

Alternatively...

void itoa_b(int n, char *s)
{
unsigned m = 0;
unsigned u = n;

if (n == 0)
m = 1;
else if (n < 0)
{
*s++ = '-';
u = -u;
if (u == 0) /* INT_MAX == UINT_MAX && n == INT_MIN */
{ *s++ = '1'; m = -1u/2+1; }
}

if (!m)
for (m = -1u/2+1; m && !(u & m); m >>= 1)
;

for (; m; m >>= 1)
*s++ = '0' + !!(u & m);

*s = 0;
}
 
L

Logan Shaw

I assumed 10 was a decimal literal and "^" was the standard bitwise
xor operator. (Yes, I was being deliberately silly.)

Yeah, it certainly could be. But it also works if 10^(10^10) is
interpreted as an expression with some binary numbers raised to
the power of some other numbers, because the value of that expression
would be (in hexadecimal) 10.
That needs to be part of the specification.

Exactly.

- Logan
 

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

Forum statistics

Threads
474,173
Messages
2,570,937
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top