LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-01-2009, 12:44 AM   #1
noir911
Member
 
Registered: Apr 2004
Posts: 682

Rep: Reputation: Disabled
signed and unsigned in C


I'm stydying C programming and going through some
network programming code. There is a header file called types.h and
the author has some typedefs on signed and unsigned char, short, int, long long, signed long long.

Can any one explain in plain English why we use signed and unsigned in network programming?

I know how to get the signed and unsigned values using sizeof().

Thanks.
 
Old 06-01-2009, 01:26 AM   #2
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 7.7 (?), Centos 8.1
Posts: 18,175

Rep: Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683
Well, types.h is just the generic definitions include used by any C program.
Having signed values means you can add/subtract eg -127 to +128
Sometimes, you may only be dealing with positive values eg counting pkts (no such thing as a negative pkt cnt), so you could use unsigned, which would mean values from 0 - 256.
However, its not specific to networking code, you just use the the type that suits you.
 
Old 06-01-2009, 04:44 AM   #3
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 178Reputation: 178
Just a couple of nits here.
Quote:
Originally Posted by chrism01 View Post
Having signed values means you can add/subtract eg -127 to +128
-128 to +127
Quote:
Originally Posted by chrism01 View Post
so you could use unsigned, which would mean values from 0 - 256
0 to 255, inclusive
 
Old 06-01-2009, 12:08 PM   #4
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
It's defined in limits.h:

Code:
/* Minimum and maximum values a `signed char' can hold.  */
#  define SCHAR_MIN	(-128)
#  define SCHAR_MAX	127

/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
#  define UCHAR_MAX	255

/* Minimum and maximum values a `signed short int' can hold.  */
#  define SHRT_MIN	(-32768)
#  define SHRT_MAX	32767

/* Maximum value an `unsigned short int' can hold.  (Minimum is 0.)  */
#  define USHRT_MAX	65535
Also, unsigned int should be used for counters because you can count to a higher number, and the values don't roll over to a negative number (if you add 1 to 32767 you will get -32768), which could wreak havoc if you don't make sure you check for such a condition ... which, lets face it, many programmers don't do ... I've seen many times errors with some large negative number in them, likely due to this rollover.
 
Old 06-01-2009, 01:53 PM   #5
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by H_TeXMeX_H View Post
Also, unsigned int should be used for counters because you can count to a higher number, and the values don't roll over to a negative number (if you add 1 to 32767 you will get -32768)
That was an important detail to remember for those of us dinosaurs who did a lot of programming with 16 bit ints.

It's not that convincing an issue with 32 bit ints. You add one to 2147483647 and get negative 2147483648. Most of the time who cares. How often do you count anything in a computer program that there are more than 2147483647 of? I work on a product that deals with massive numbers of objects in very massive amounts of memory and 2147483647 bytes is relatively small. But almost nothing in the code counts bytes. We count various objects and we never need to count as high as 2147483647 objects.

Maybe you should use unsigned int for counters just as a matter of style, because values that are actually unsigned should use an unsigned data type even if there are enough bits to spare that it wouldn't matter at run time. But in the list of good practices that most programmers ought to follow and don't, I think this one wouldn't hit the top hundred.

In performance critical x86_64 code, I am careful to use unsigned int for loop indexes and array (both C array and vector) indexes, because the x86_64 architecture is most efficient when indexes are 32 bit unsigned (as opposed to either signed or 64 bit). However, worrying about that level of detail also means you must follow through with some strange extra details. Consider simple and common constructs such as
Code:
something[ndx+1]
In 32 bit x86, you'll get pretty much the same code whether ndx is int or unsigned int or std::size_t. But in 64 bit, you may get good or bad code (depending on context) for std::size_t and you'll usually (but still depending on context) get worse code when ndx is int or unsigned int.
To usually get good code, ndx must be unsigned int and you must code it equivalent to
Code:
something[ndx+1L]
or
Code:
(something+1)[ndx]
Notice using 1L instead of 1 in code like that makes zero difference in 32 bit code and makes zero difference when ndx is std::size_t and even tends to make zero difference when ndx is int. But in x86_64 code when ndx is unsigned int, that L makes a big difference (all the way from typically worse than when ndx is std:size_t to typically better) and usually is the only clean way to get the best code.

So if you're pushing for really best code, you might use unsigned int for indexes for the above reason, but that is worthwhile only if you follow through with all the details.

Last edited by johnsfine; 06-01-2009 at 02:27 PM.
 
Old 06-01-2009, 02:39 PM   #6
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by johnsfine View Post
That was an important detail to remember for those of us dinosaurs who did a lot of programming with 16 bit ints.

It's not that convincing an issue with 32 bit ints. You add one to 2147483647 and get negative 2147483648. Most of the time who cares. How often do you count anything in a computer program that there are more than 2147483647 of? I work on a product that deals with massive numbers of objects in very massive amounts of memory and 2147483647 bytes is relatively small. But almost nothing in the code counts bytes. We count various objects and we never need to count as high as 2147483647 objects.

Maybe you should use unsigned int for counters just as a matter of style, because values that are actually unsigned should use an unsigned data type even if there are enough bits to spare that it wouldn't matter at run time. But in the list of good practices that most programmers ought to follow and don't, I think this one wouldn't hit the top hundred.

In performance critical x86_64 code, I am careful to use unsigned int for loop indexes and array (both C array and vector) indexes, because the x86_64 architecture is most efficient when indexes are 32 bit unsigned (as opposed to either signed or 64 bit). However, worrying about that level of detail also means you must follow through with some strange extra details. Consider simple and common constructs such as
Code:
something[ndx+1]
In 32 bit x86, you'll get pretty much the same code whether ndx is int or unsigned int or std::size_t. But in 64 bit, you may get good or bad code (depending on context) for std::size_t and you'll usually (but still depending on context) get worse code when ndx is int or unsigned int.
To usually get good code, ndx must be unsigned int and you must code it equivalent to
Code:
something[ndx+1L]
or
Code:
(something+1)[ndx]
Notice using 1L instead of 1 in code like that makes zero difference in 32 bit code and makes zero difference when ndx is std::size_t and even tends to make zero difference when ndx is int. But in x86_64 code when ndx is unsigned int, that L makes a big difference (all the way from typically worse than when ndx is std:size_t to typically better) and usually is the only clean way to get the best code.

So if you're pushing for really best code, you might use unsigned int for indexes for the above reason, but that is worthwhile only if you follow through with all the details.
For indexes one should use 'size_t' type - that's universal/cross-platform:

http://en.wikipedia.org/wiki/Size_t
http://www.embedded.com/columns/prog...ters/200900195
http://www.cplusplus.com/reference/c...string/size_t/
.
 
Old 06-01-2009, 02:56 PM   #7
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
Quote:
Originally Posted by johnsfine View Post
That was an important detail to remember for those of us dinosaurs who did a lot of programming with 16 bit ints.
Yeah, it's true, that was for 16 bit short int. But, who know, maybe somebody still uses them ? Using 32-bit int would be a better idea.

The rolling over also affects chars, which are still used, so that may affect things if you use them as integers.
 
Old 06-01-2009, 11:53 PM   #8
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 7.7 (?), Centos 8.1
Posts: 18,175

Rep: Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683Reputation: 2683
@johnsfine: You should use signed/unsigned as appropriate, just in case; eg I wrote a program for an ISP, that tracked download/upload usage; definitely needed the larger unsigned number!
 
Old 06-02-2009, 07:46 AM   #9
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by chrism01 View Post
@johnsfine: You should use signed/unsigned as appropriate, just in case;
I do use signed vs. unsigned as appropriate. I was just suggesting that for ordinary programming getting that right isn't nearly as important as it was back when ints were typically 16 bits.

I intentionally do not use unsigned int vs. std::size_t as "appropriate". I use
typedef unsigned int index_t;
and then use index_t for almost all loop indexes and variables used in subscripting arrays and vectors. I know that I don't need to worry about the number of items indexed hitting 4G. The code is built for several platforms and on the one where 64 bit indexes are faster, I just conditionalize that one line to
typedef std::size_t index_t;
But on the main platform (x86_64) it runs faster with index_t as unsigned int. (and of course on 32 bit it makes no difference whether index_t is unsigned int or std::size_t).
Maybe in some distant future version we will need to worry about indexes over 4G. That is another good reason for using a typedef rather than using unsigned int or std::size_t directly. It is easy to change the data types of all the indexes in the project by changing one conditional in one header.

Quote:
eg I wrote a program for an ISP, that tracked download/upload usage; definitely needed the larger unsigned number!
So 31 bits (the positive range of a signed int) is "definitely" not enough for those usage stats and therefor you chose to use 32 bits ??!

You picked a very poor example for justifying correct choice of signed vs. unsigned.
 
Old 06-02-2009, 08:24 AM   #10
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 178Reputation: 178
Quote:
Originally Posted by johnsfine View Post
So 31 bits (the positive range of a signed int) is "definitely" not enough for those usage stats and therefor you chose to use 32 bits ??!

You picked a very poor example for justifying correct choice of signed vs. unsigned.
To make the argument more explicit:

If you definitely know that 31 bits are not enough, and for now 32 bits seem enough, how long will it be before you need 33 bits? Using a variable that's just barely large enough, when measuring usage stats, seems likely to fail in the future.

By "fail", I don't mean your program will crash. I mean that the statistics will just overflow without warning, and the program will hum and whistle and blink its eyes innocently and keep right on going and giving you bad results. That's much worse than crashing. You'll never know it's happening.

Friend, if you know that 31 bits aren't enough for usage stats, go get yourself 63 or 64 bits. Or something.
 
Old 06-02-2009, 08:58 AM   #11
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
I did a lot of programming in an environment with 16 bit ints, expensive 32 bit longs, and more than 65KB of total data. Selecting signed vs. unsigned ints correctly was very important. It's getting hard now to remember why, but it was so common then to be counting something for which the 15 bit positive range of an int was not enough, but the 16 bit unsigned range was (or if it wasn't, so many other limits would be exceeded that the unsigned int would be the least of the problems).

I can't exactly explain why, but I'm sure something is qualitatively rather than quantitatively different now.

I'm now working with 32 bit ints, relatively inexpensive 64 bit longs, and more than 4GB of total data. I usually use signed vs. unsigned correctly as a matter of style rather than need. There is nothing other than total memory use or total files sizes, that can't be counted with 29 bits, so for all the ordinary counters the 31 bit positive range is just as good as the 32 bit unsigned range. For total memory or file sizes, 32 bits is just as bad as 31. As things grow in the future, there will be a short lived and barely more than accidental period in which some counters could work in 32 bits but not in 31. As with my opinion of the network stats discussed above, by the time you notice 31 bits isn't enough, 32 bits isn't either.

Whatever effect made so many unsigned values fit in 16 bits but not 15, just isn't going to repeat at the 31/32 boundary. It also is worth noting that 64 bit longs have become relatively cheap before many of the things programs count needed more than 31 bits. In the most common architectures, 32 bit longs were much more expensive than 16 bit values long after counting more than 32767 things in a program was common. So long ago, if the count didn't fit in 15 bits it was rational to ask does it fit in 16. Now, if it doesn't fit in 31, you're silly to use less than 63.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
unsigned long int uint32_t to unsigned char and back MicahCarrick Programming 2 08-02-2009 01:39 AM
signed/unsigned int and vector::size() [KIA]aze Programming 1 11-23-2007 06:19 PM
Problem with sending a signed int to another signed int. Almost random number given. RHLinuxGUY Programming 8 08-15-2006 11:38 AM
signed and unsigned ArthurHuang Programming 4 05-23-2006 03:46 AM
convert unsigned char * to unsigned long int linux_lover2005 Programming 3 04-26-2005 11:38 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:36 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration