As a small experiment, I wrote an elementary C program to display min and max values of the basic object types.

/* Display min/max limits using limits.h header file */ 

#include <stdio.h>    /* printf */
#include <limits.h>   /* limits */
#include <assert.h>   /* assert */

#define COMPUTE 1
/* used values:
 *
 * 0 - do not calculate min/max values
 * 1 - calculate min/max values with exceptions for "long" types
 * 2 - calculate min/max values without any exceptions */

/* calculate max value */
#define max(var, temp) \
  var=0; temp=0;       \
  while((++var)>0)     \
    temp++;

/* calculate min value */
#define min(var, temp) \
  var=0; temp=0;       \
  while((--var)<0)     \
    temp--;

/* print description and min/max limits using limits.h */
#define describe(description, type,  min, max) \
  printf("%s\n\tlimits.h:   <%" type ", %" type ">\n", \
         description, min, max);

/* calculate and print min/max values */
#define calculate(var, type, vmin, vmax) \
  min(var, vmin); \
  max(var, vmax); \
  printf("\tcalculated: <%" type ", %" type ">\n", \
         vmin, vmax);


int main()
{

  /* signed char */
  describe("signed char", "hhd", SCHAR_MIN, SCHAR_MAX);
# if COMPUTE 
    signed char schar, schar_max, schar_min;
    calculate(schar, "hhd", schar_min, schar_max);
    assert(schar_min == SCHAR_MIN && schar_max == SCHAR_MAX);
# endif

  /* unsigned char */
  describe("unsigned char", "hhu", 0, UCHAR_MAX);
# if COMPUTE
    unsigned char uchar, uchar_min, uchar_max;
    calculate(uchar, "hhu", uchar_min, uchar_max);
    assert(uchar_min == 0 && uchar_max == UCHAR_MAX);
# endif

  /* char */
  describe("char", "hhd", CHAR_MIN, CHAR_MAX);
# if COMPUTE
    char character, char_min, char_max;
    calculate(character, "hhd", char_min, char_max);
    assert(char_min == CHAR_MIN && char_max == CHAR_MAX);
# endif
 
  /* signed short int */
  describe("signed short int", "hd", SHRT_MIN, SHRT_MAX);
# if COMPUTE
    signed short int ssint, ssint_min, ssint_max;
    calculate(ssint, "hd", ssint_min, ssint_max);
    assert(ssint_min == SHRT_MIN && ssint_max == SHRT_MAX);
# endif

  /* unsigned short int */
  describe("unsigned short int", "hu", 0, USHRT_MAX);
# if COMPUTE
    unsigned short int usint, usint_min, usint_max;
    calculate(usint, "hu", usint_min, usint_max);
    assert(usint_min == 0 && usint_max == USHRT_MAX);
# endif

  /* signed long int */
  describe("signed long int", "ld", LONG_MIN, LONG_MAX);
# if COMPUTE == 2
    signed long int slint, slint_min, slint_max;
    calculate(slint, "ld", slint_min, slint_max);
    assert(slint_min == LONG_MIN && slint_max == LONG_MAX);
# endif

  /* unsigned long int */
  describe("unsigned long int", "lu", (unsigned long int) 0, ULONG_MAX);
# if COMPUTE == 2
    unsigned long int ulint, ulint_min, ulint_max;
    calculate(ulint, "lu", ulint_min, ulint_max);
    assert(ulint_min == 0 && ulint_max == ULONG_MAX);
# endif

#if defined __USE_ISOC99  && defined __GNUC__
    /* signed long long int */
    describe("signed long long int", "lld", LLONG_MIN, LLONG_MAX);
#   if COMPUTE == 2
      signed long long int sllint, sllint_min, sllint_max;
      calculate(sllint, "lld", sllint_min, sllint_max);
      assert(sllint_min == LLONG_MIN && sllint_max == LLONG_MAX);
#   endif

    /* unsigned long long int */
    describe("unsigned long long int", "llu", \
             (unsigned long long int) 0, ULLONG_MAX);
#   if COMPUTE == 2
      unsigned long long int ullint, ullint_min, ullint_max;
      calculate(ullint, "llu", ullint_min, ullint_max);
      assert(ullint_min == 0 && ullint_max == ULLONG_MAX);
#   endif
#endif

  /* signed int */
  describe("signed int", "d", INT_MIN, INT_MAX);
# if COMPUTE 
    signed int sint, sint_min, sint_max;
    calculate(sint, "d", sint_min, sint_max);
    assert(sint_min == INT_MIN && sint_max == INT_MAX);
# endif

  /* unsigned int */
  describe("unsigned int", "u", 0, UINT_MAX);
# if COMPUTE 
    unsigned int uint, uint_min, uint_max;
    calculate(uint, "u", uint_min, uint_max);
    assert(uint_min == 0 && uint_max == UINT_MAX);
# endif

  return 0;
}

Sample output:

$ gcc limits.c -o limits
$ ./limits
signed char
	limits.h:   <-128, 127>
unsigned char
	limits.h:   <0, 255>
char
	limits.h:   <-128, 127>
signed short int
	limits.h:   <-32768, 32767>
unsigned short int
	limits.h:   <0, 65535>
signed long int
	limits.h:   <-9223372036854775808, 9223372036854775807>
unsigned long int
	limits.h:   <0, 18446744073709551615>
signed long long int
	limits.h:   <-9223372036854775808, 9223372036854775807>
unsigned long long int
	limits.h:   <0, 18446744073709551615>
signed int
	limits.h:   <-2147483648, 2147483647>
unsigned int
	limits.h:   <0, 4294967295>

Sample output (ISO C90 standard):

$ gcc -std=c89 limits.c -o limits
$ ./limits
signed char
	limits.h:   <-128, 127>
unsigned char
	limits.h:   <0, 255>
char
	limits.h:   <-128, 127>
signed short int
	limits.h:   <-32768, 32767>
unsigned short int
	limits.h:   <0, 65535>
signed long int
	limits.h:   <-9223372036854775808, 9223372036854775807>
unsigned long int
	limits.h:   <0, 18446744073709551615>
signed int
	limits.h:   <-2147483648, 2147483647>
unsigned int
	limits.h:   <0, 4294967295>

To calculate min and max values, modify the COMPUTE constant in the source code.

$ gcc limits.c -o limits
$ ./limits
signed char
	limits.h:   <-128, 127>
	calculated: <-128, 127>
unsigned char
	limits.h:   <0, 255>
	calculated: <0, 255>
char
	limits.h:   <-128, 127>
	calculated: <-128, 127>
signed short int
	limits.h:   <-32768, 32767>
	calculated: <-32768, 32767>
unsigned short int
	limits.h:   <0, 65535>
	calculated: <0, 65535>
signed long int
	limits.h:   <-9223372036854775808, 9223372036854775807>
unsigned long int
	limits.h:   <0, 18446744073709551615>
signed long long int
	limits.h:   <-9223372036854775808, 9223372036854775807>
unsigned long long int
	limits.h:   <0, 18446744073709551615>
signed int
	limits.h:   <-2147483648, 2147483647>
	calculated: <-2147483648, 2147483647>
unsigned int
	limits.h:   <0, 4294967295>
	calculated: <0, 4294967295>

Read about -fno-strict-overflow and -fwrapv arguments if you want to use gcc optimization flags.

$ gcc -Os -fwrapv limits.c -o limits