user23991: In my Arduino projects I use both Arduino types and types defined in the "inttypes.h" file, which #includes stdint.h. So far I've always written code only for the ATmega328P microcontroller (either in the UNO board or "standalone").
To be clear, in this question I'm referring to the following types:

"Arduino": char, int, long; byte, word, unsigned long
inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t



What is the actual difference between e.g. int and int16_t?
Is implicit conversion between corresponding types always possible, or should I avoid it even if the compiler doesn't complain? (quite often in my programs I pass an int16_t as int argument to a function and it always works, but is it good practice to do it, in general?


user31105: int can be depending on the hardware architecture and is mostly 16 or 32 bit. 
However, an int16_t is always 16 bit, regardless of the hardware architecture.
It will go wrong when you have a 32 bit architecture (for an int), and you are going to cast it to an int16_t, than you lose the MSB 16 bits. Although I think the compiler will give a warning in this case (so in your case you are ok, but it can prevent a lot of work when you port your code to a 32 bit architecture).
However, all Arduinos have int defined as 16 bit, except the Due and SAMD based boards, see: Arduino reference for int (updated after the comment of per1234 below, thanks for that).
Normally I use integer when I don't care much about the type (and know it will stay under 32768, like for most indices in loops). But if you define a (large) array it's better to use an explicit type, or if you know for sure the value will never be higher than 32768 (int8_t) or nonnegative and 65535 (uint8_t).
Also, for the 'eye' unsigned char for an unsigned 'integer' value upto 255, uint8_t looks better than a 'char' which seems more like a character instead of a value.

user7508: 

"Arduino": char, int, long; byte, word, unsigned long
inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t


A better classification would be:

C and C++: char, int, long, unsigned long
"Arduino": byte, word
inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t

I generally avoid the Arduino-specific types, as they are quite
non-standard, and do not usually exist outside the Arduino world. As for
the other types, just like Michel Keijzers suggests, I use the C types
when I do not care much about the exact size. int is guaranteed to be
at least 16 bits, but is likely to be 32 bits on a 32-bit architecture.
It is a good default type, as it is supposed to be efficiently handled
on any architecture. These types allow you to write portable code that
automatically selects the "right" integer width for whatever
architecture it is been compiled for.
If you care about the exact size, which can often be the case in a
memory-constrained environment, use the types from inttypes.h. And do
not worry about implicit conversions: as long as both types are wide
enough to hold the numbers you need to store, a type conversion, whether
implicit or explicit, always preserves the value.

23991: <p>In my Arduino projects I use both Arduino types and types defined in the "inttypes.h" file, which #includes stdint.h. So far I've always written code only for the ATmega328P microcontroller (either in the UNO board or "standalone").</p>

<p>To be clear, in this question I'm referring to the following types:</p>

<ul>
<li>"Arduino": <code>char</code>, <code>int</code>, <code>long</code>; <code>byte</code>, <code>word</code>, <code>unsigned long</code></li>
<li>inttypes: <code>int8_t</code>, <code>int16_t</code>, <code>int32_t</code>; <code>uint8_t</code>, <code>uint16_t</code>, <code>uint32_t</code></li>
</ul>

<hr>

<ul>
<li>What is the actual difference between e.g. <code>int</code> and <code>int16_t</code>?</li>
<li>Is implicit conversion between corresponding types always possible, or should I avoid it even if the compiler doesn't complain? (quite often in my programs I pass an <code>int16_t</code> as <code>int</code> argument to a function and it always works, but is it good practice to do it, in general?</li>
</ul>
 31105: <p>int can be depending on the hardware architecture and is mostly 16 or 32 bit. 
However, an int16_t is always 16 bit, regardless of the hardware architecture.</p>

<p>It will go wrong when you have a 32 bit architecture (for an int), and you are going to cast it to an int16_t, than you lose the MSB 16 bits. Although I think the compiler will give a warning in this case (so in your case you are ok, but it can prevent a lot of work when you port your code to a 32 bit architecture).</p>

<p>However, all Arduinos have int defined as 16 bit, except the Due and SAMD based boards, see: <a href="https://www.arduino.cc/en/Reference/Int" rel="nofollow noreferrer">Arduino reference for int</a> (updated after the comment of per1234 below, thanks for that).</p>

<p>Normally I use integer when I don't care much about the type (and know it will stay under 32768, like for most indices in loops). But if you define a (large) array it's better to use an explicit type, or if you know for sure the value will never be higher than 32768 (int8_t) or nonnegative and 65535 (uint8_t).</p>

<p>Also, for the 'eye' unsigned char for an unsigned 'integer' value upto 255, uint8_t looks better than a 'char' which seems more like a character instead of a value.</p>
 7508: <blockquote>
  <ul>
  <li>"Arduino": <code>char</code>, <code>int</code>, <code>long</code>; <code>byte</code>, <code>word</code>, <code>unsigned long</code></li>
  <li>inttypes: <code>int8_t</code>, <code>int16_t</code>, <code>int32_t</code>; <code>uint8_t</code>, <code>uint16_t</code>, <code>uint32_t</code></li>
  </ul>
</blockquote>

<p>A better classification would be:</p>

<ul>
<li>C and C++: <code>char</code>, <code>int</code>, <code>long</code>, <code>unsigned long</code></li>
<li>"Arduino": <code>byte</code>, <code>word</code></li>
<li>inttypes: <code>int8_t</code>, <code>int16_t</code>, <code>int32_t</code>; <code>uint8_t</code>, <code>uint16_t</code>, <code>uint32_t</code></li>
</ul>

<p>I generally avoid the Arduino-specific types, as they are quite
non-standard, and do not usually exist outside the Arduino world. As for
the other types, just like Michel Keijzers suggests, I use the C types
when I do not care much about the exact size. <code>int</code> is guaranteed to be
at least 16 bits, but is likely to be 32 bits on a 32-bit architecture.
It is a good default type, as it is supposed to be efficiently handled
on any architecture. These types allow you to write portable code that
automatically selects the "right" integer width for whatever
architecture it is been compiled for.</p>

<p>If you care about the exact size, which can often be the case in a
memory-constrained environment, use the types from inttypes.h. And do
not worry about implicit conversions: as long as both types are wide
enough to hold the numbers you need to store, a type conversion, whether
implicit or explicit, always preserves the value.</p>
