float, double."> float, double." />

The explanation assumes the case of tml "> float, double.

When converting from a floating-point type with a large bit width to a floating-point type with a small bit width, if the value before the change exceeds the number of significant digits that the changed type can represent, the number of significant digits after the change is changed. Maximum number of significant digits that the type can represent.

#include <stdio.h>

int main (void) {
  
  // Convert from double type to float type
  double num_d = 2.111111111111111111111111111111;
  float num_f = num_d;
  
  printf("double:%.50f\nfloat:%.50f\n", num_d, num_f);
}

This is the output result. You can see that the accuracy has dropped.

double: 2.11111111111111116045435665000695735216140747070312
float: 2.11111116409301757812500000000000000000000000000000

Conversion from signed integer type to floating point type (with information loss)

Describes the conversion from signed integer type to floating point type.

Numerical information may be lost when converting signed integer types to floating point types.

The double type is 64bit. The maximum integer type that can be correctly represented by double type is int32_t type. For int64_t type, numeric information may be lost.

The float type is 64bit. The maximum integer type that can be correctly expressed by float type is int16_t type. In the case of int64_t type and int32_t type, numerical information may be lost.

This is a sample when the conversion is successful.

#include <stdio.h>
#include <stdint.h>

int main (void) {
  
  // Convert from int32_t type to double type
  int32_t num_i32 = INT32_MAX;
  double num_d = num_i32;
  
  printf("%f\n", num_d);
}

This is the output result. The maximum value INT32_MAX (2147483647) of int32_t type can be expressed by double type.

2147483647.000000

This is a sample in which numerical information is lost.

#include <stdio.h>
#include <stdint.h>

int main (void) {
  
  // Convert from int32_t type to float type
  int32_t num_i32 = INT32_MAX;
  float num_f = num_i32;
  
  printf("%f\n", num_f);
}

This is the output result. Ah, the accuracy wasn't enough, so if you look closely, the value has changed.

2147483648.000000

Conversion from floating point type to signed integer type (with information loss)

Describes the conversion from floating-point type to signed integer type.

Converting from a floating-point type to a signed integer type removes the information after the decimal point.

If double is a conversion to int64_t type, there is no information loss. Information loss may occur if the number of bits is less than that of a signed integer type.

If float is converted to int32_t type, there is no information loss. Information loss may occur if the number of bits is less than that of a signed integer type.

This is a sample when the conversion is successful.

#include <stdio.h>
#include <stdint.h>

int main (void) {
  
  // Convert from int32_t type to double type
  double num_d = 33.43;
  int64_t num_i64 = num_d;
  
  printf("%d\n", num_i64);
}

This is the output result.

33 33

Mutual conversion between signed integer type and unsigned integer type of the same size (no information loss)

This section describes the mutual conversion between signed and unsigned integer types of the same size.

As a signed integer type, int8_t, int16_t, int32_t, int64_t.

As an unsigned integer type, uint8_t, uint16_t, uint32_t, uint64_t.

Mutual conversion between signed and unsigned integers of the same size does not change the internal bit representation. It is only a conversion that means whether the internal bit representation is interpreted as signed or unsigned.

This is a sample that converts between signed and unsigned integer types of the same size.

#include <stdio.h>
#include <stdint.h>

int main (void) {
  int8_t num_i8 = -1;
  uint8_t num_ui8 = num_i8;
  
  printf("num_ui8:%d\n", num_ui8);
  
  int8_t num_i8_again = num_ui8;
  
  printf("num_i8_again:%d\n", num_i8_again);
}

Output result.

num_ui8: 255
num_i8_again: -1

No conversion has been done at the bit level. Negative values ​​are assumed to be represented by two's complement.

// -1 8bit signed integer
11111111

// 255 8bit unsigned integer
11111111

Mutual conversion of different pointer types

Conversion between different pointer types will give a warning in a typical C compiler. In almost all cases, this is an unintended behavior by the author and is considered a bug.

#include <stdint.h>

int main (void) {
  int32_t * nums_i32_ptr;
  int8_t * nums_i8_ptr = nums_i32_ptr;
}

The content of the warning in gcc.

Please refer to the following articles for pointers.

Mutual conversion between general-purpose pointer type "void *" and pointer type

General-purpose pointer type "void *" and pointer type are allowed to be converted to each other in C language by design in either direction. This is the behavior that C language expects, so even if you do not typecast, you will not be warned. I'll write this because I feel "Oh, is this okay?" When type checking is familiar with strict programming languages.

However, if the data pointed to by the general-purpose pointer type is assigned to an unintended pointer type, it is a mistake for the program, so be careful.

#include <stdint.h>

int main (void) {
  int32_t * nums_i32_ptr;
  
  // Type conversion from other pointer types to generic pointer types
  void * void_ptr = nums_i32_ptr;
  
  // Type conversion from generic pointer types to other pointer types
  int32_t * nums_i32_ptr2 = void_ptr;
}

Convert pointer type to integer type without warning, and vice versa

Here's how to convert a pointer type to an integer type without warning. Also, I will write about how to do the reverse conversion without issuing a warning.

If you convert general-purpose pointer type "void *" to a signed integer type or an unsigned integer type, a warning will be issued in general processing systems. Occurs.

A warning is also issued for the reverse conversion.

Such a transformation is generally a mistake, but ideally you don't want to share a container of data between the object "void *" and the integer "int32_t" (or a 32-bit floating point float). But in practice, there are times when you want to do it because you don't want to write duplicate code.

In such a case, I will describe how to perform type conversion without issuing a warning. We use a special type called intptr_t. intptr_t is a signed integer type that is guaranteed to be the same size as the pointer type, and allows conversion between pointer type and signed integer type. For unsigned integer types, there is also a type called uintptr_t.

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

int main (void) {
  // General purpose container
  void ** elements = calloc (sizeof (void *), 10);
  
  // I want to save a 32-bit integer type here. Because it will be a double implementation of implementing the container for 32-bit integers.
  // For the time being, I want to make it in time
  int32_t num = 100;
  elements [0] = (void *) (intptr_t) num;
  
  // take out
  int32_t num_again = (intptr_t) elements [0];
  
  printf("%d\n", num_again);
}

This is the output result.

100

This is strictly a mistake (out for 16-bit CPU processing systems), but it is a correct program assuming that 32-bit or higher CPU processing systems are all in the world.

Isn't the above explanation an explanation of the type conversion rules in the C language specification?

Associated Information