user65866: I have been testing on an Arduino UNO various techniques for serial printing from Flash Memory instead of RAM. At the same time, I have been using the freeMemory() function from Adafruit.
I created a program that prints the word "test", with various methods:

Simple print: 

Serial.print("test");
Serial.print(freeMemory());

This call reports free RAM = 2267

Using the F() Macro: 

Serial.print(F("test"));
Serial.print(freeMemory());

This call reports free RAM = 2299

Using sprintf_P()

char buf[100];
sprintf_P(buf,PSTR("test"));
Serial.print(buf);
Serial.print(freeMemory());

This call reports free RAM = 2267

Using strcpy_P()

 char buf[100];
 strcpy_P(buf, (PGM_P)F("test"));
 Serial.print(buf);
Serial.print(freeMemory());

This call reports free RAM = 2267

Using strcpy_P and const char[] PROGMEM 

char buf[100];
const char buff[] PROGMEM = "test";
strcpy_P(buf, buff);
Serial.print(buf);
Serial.print(freeMemory());

This call reports free RAM = 2267
The basic point of this question is to gather all the possible Flash memory printing techniques. Also it would be really useful if you could explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.
IMPORTANT EDIT1:
Depending on where and how I use the call Serial.print(freeMemory()); the results change. For example, at the last example (PROGMEM, strcpy_P) when I included another Serial.print(freeMemory()); before the call of the printing functions, then both freeMemory() calls report 2299!
Another interesting problem is that the freeMemory() reports 2299 as freeRam, while the SRAM of my arduino UNO is only 2kbytes.
EDIT2:
Following the suggestion in comments, I changed "test" to "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest". Now all different methods report a free ram of 2299, including the simple Serial.print().
freeMemory():
#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else  // __ARM__
extern char *__brkval;
#endif  // __arm__     
int freeMemory() {
  char top;
#ifdef __arm__
  return &top - reinterpret_cast<char*>(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
  return &top - __brkval;
#else  // __arm__
  return __brkval ? &top - __brkval : &top - __malloc_heap_start;
#endif  // __arm__
}


user4143: 
explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.


F() wraps the string literal in PSTR(...) and then casts it to __FlashStringHelper.  This forces it to remain in flash and also gives it a type that the Arduino core can identify as a string in flash for overloading.
PGM_P is a "Pointer to ProGraM mememory". This is the type that all the _P variants of functions require. It's basically const char * provided by avr/pgmspace.h
const PROGMEM is actually two things. const means you're not changing the value, and PROGMEM is another name for __ATTR_PROGMEM__ which itself is an alias for __attribute__((__progmem__)) which is a flag for the compiler to tell it to keep the variable in flash and not copy it to RAM.

So F() and PGM_P are used when you are passing a string literal to a function that expects one of those formats. PROGMEM is used when you're setting up a constant "variable" (oxymoron there, I know...) that points to data in flash.

user40646: First, the freeMemory() function that you used from Adafruit was originated from a github, I don't know about the __arm__ implementation, but for the avr, it is incomplete for handling the corner case when the program does not use the malloc() function, if your program never use malloc(), the formula used in freeMemory() will produce the wrong result. A simple corrected version for AVR that I used is here:
extern unsigned int __heap_start;
extern char *__brkval;

int freeMemory() {
  char top_of_stack;

  if (__brkval == 0) {
    Serial.println(((int)&top_of_stack - (int)&__heap_start));
  } else {
    Serial.println((int)&top_of_stack - (int)__brkval);
  }
}


explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.

PSTR("string literal")
PSTR came into Arduino from part of avr-libs(a C library) defined in avr/pgmspace.h, it is actually a macro, not a function as many think it was, and is defined as:
#define     PSTR(s)   ((const PROGMEM char *)(s))

It looks a little bit intimidated but it actually quite simple, it not only tell the avr-gcc that the string literal s should be kept in program memory (i.e. Flash memory in the case of Arduino), but allows the program to convert it into a const char *s PROGMEM variable so that it can be pass around into some PROGMEM-aware functions as a parameter.
 //this is a PROGMEM-aware function in c
 printMsg_P(const char* str) {
     char buf[strlen_P(str)+1];
     strcpy_P(buf, str);
     puts(buf);
 }

 // this handle the normal string array function
 printMsg(const char* str) {
     puts(str);
 }

F("string literal")
F() is also a macro but it is not part of the avr/progmem.h, it is actually part of the String class defined in WString.h together with a definition of a class called __FlashStringHelper:
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

To understand the F() macro and the difference between F() and PSTR() take a little bit explanation.
As you can see from the definition of F(), it casts a string literal into a const char* variable using PSTR(), and then re-cast it into a class __FlashStrngHelper. If you further looks at the __FlashStringHelper, it is actually an empty class without any construct or method, it is literally empty, so why is this useful? and why can't just pass the string literal around by just using PSTR().
This has to do with C++'s function overload. Function overload is a feature of C++ where multiple methods could have the same function name but each with different parameters. Within all the Serial.print() methods, there is a method Serial.print(const char* str) that will take in a string literal and print it to serial monitor, but it is not PROGMEM-aware, if you pass in a PROGMEM string literal Serial.print(PSTR("string literal"));, the same method will accept what you pass in because it meet the type checking (remember PSTR is actually const char*), but it will not print out the correct string for PSTR("string literal") because it simply expecting a normal string.
In c, as we see before, we solves the problem by using two functions with different names for handling normal string and PROGMEM string, but Serial is a C++ class, it needs another function overloaded method to be PROGMEM-aware, and PSTR() is clearly not the solution as we just mentioned.
What WSting.h and Print.cpp did is to create an overload method that is PROGMEM-aware by accepting a class as parameter, so that you can pass a F() wrapped string literal which has a data type of class __FlashStringHelper into the Serial.print() and get the print out correctly from program memory. See the source code yourself.
Serial.print(const __FlashStringHelper *ifsh)

So in summary, the F() and PSTR() are alike, both telling the compiler to keep the string literal in the program memory, and allow the string literal to be pass around into some function as parameter. But it was designed for different purpose from different programming paradigm (C versus C++). F() is Serail.print()-friendly, while PSTR() is not. If you are getting PSTR() in a function and yet you want to send it to Serial.print(), you will have to explicitly cast it into __FlashStringHelper like this:
Serial.print((__FlashStringHelper*)PSTR("test"));

PGM_P
PGM_P is a macro defined as:
#define     PGM_P   const char *

Whether you want to use PGM_P or const char * is a personal preference, for example, this is copy from https://www.arduino.cc/reference/en/language/variables/utilities/progmem/:
const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

can be written as:
PGM_P const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

This is a lengthy explanation, but I hope this will help on better understand the subject and therefore be able to use the PROGMEM and all the associated macros effectively.

65866: <p>I have been testing on an Arduino UNO various techniques for serial printing from Flash Memory instead of RAM. At the same time, I have been using the <a href="https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory" rel="nofollow noreferrer">freeMemory()</a> function from Adafruit.</p>

<p>I created a program that prints the word "test", with various methods:</p>

<ul>
<li>Simple print: </li>
</ul>

<pre><code>Serial.print("test");
Serial.print(freeMemory());
</code></pre>

<p>This call reports free RAM = 2267</p>

<ul>
<li>Using the F() Macro: </li>
</ul>

<pre><code>Serial.print(F("test"));
Serial.print(freeMemory());
</code></pre>

<p>This call reports free RAM = 2299</p>

<ul>
<li>Using sprintf_P()</li>
</ul>

<pre><code>char buf[100];
sprintf_P(buf,PSTR("test"));
Serial.print(buf);
Serial.print(freeMemory());
</code></pre>

<p>This call reports free RAM = 2267</p>

<ul>
<li>Using strcpy_P()</li>
</ul>

<pre><code> char buf[100];
 strcpy_P(buf, (PGM_P)F("test"));
 Serial.print(buf);
Serial.print(freeMemory());
</code></pre>

<p>This call reports free RAM = 2267</p>

<ul>
<li>Using strcpy_P and const char[] PROGMEM </li>
</ul>

<pre><code>char buf[100];
const char buff[] PROGMEM = "test";
strcpy_P(buf, buff);
Serial.print(buf);
Serial.print(freeMemory());
</code></pre>

<p>This call reports free RAM = 2267</p>

<p><strong>The basic point of this question is to gather all the possible Flash memory printing techniques. Also it would be really useful if you could explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.</strong></p>

<p><strong>IMPORTANT EDIT1:</strong>
Depending on where and how I use the call <code>Serial.print(freeMemory());</code> the results change. For example, at the last example (PROGMEM, strcpy_P) when I included another <code>Serial.print(freeMemory());</code> before the call of the printing functions, then both freeMemory() calls report 2299!</p>

<p>Another interesting problem is that the freeMemory() reports 2299 as freeRam, while the SRAM of my arduino UNO is only 2kbytes.</p>

<p><strong>EDIT2:</strong>
Following the suggestion in comments, I changed "test" to "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest". Now all different methods report a free ram of 2299, including the simple <code>Serial.print()</code>.</p>

<p>freeMemory():</p>

<pre><code>#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else  // __ARM__
extern char *__brkval;
#endif  // __arm__     
int freeMemory() {
  char top;
#ifdef __arm__
  return &amp;top - reinterpret_cast&lt;char*&gt;(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO &gt; 103 &amp;&amp; ARDUINO != 151)
  return &amp;top - __brkval;
#else  // __arm__
  return __brkval ? &amp;top - __brkval : &amp;top - __malloc_heap_start;
#endif  // __arm__
}
</code></pre>
 4143: <blockquote>
  <p>explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.</p>
</blockquote>

<ul>
<li><code>F()</code> wraps the string literal in <code>PSTR(...)</code> and then casts it to <code>__FlashStringHelper</code>.  This forces it to remain in flash and also gives it a type that the Arduino core can identify as a string in flash for overloading.</li>
<li><code>PGM_P</code> is a "Pointer to ProGraM mememory". This is the type that all the <code>_P</code> variants of functions require. It's basically <code>const char *</code> provided by <code>avr/pgmspace.h</code></li>
<li><code>const PROGMEM</code> is actually two things. <code>const</code> means you're not changing the value, and <code>PROGMEM</code> is another name for <code>__ATTR_PROGMEM__</code> which itself is an alias for <code>__attribute__((__progmem__))</code> which is a flag for the compiler to tell it to keep the variable in flash and not copy it to RAM.</li>
</ul>

<p>So <code>F()</code> and <code>PGM_P</code> are used when you are passing a string literal to a function that expects one of those formats. <code>PROGMEM</code> is used when you're setting up a constant "variable" (oxymoron there, I know...) that points to data in flash.</p>
 40646: <p>First, the <a href="https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory" rel="nofollow noreferrer">freeMemory()</a> function that you used from Adafruit was originated from a <a href="https://github.com/mpflaga/Arduino-MemoryFree" rel="nofollow noreferrer">github</a>, I don't know about the <code>__arm__</code> implementation, but for the avr, it is incomplete for handling the corner case when the program does not use the <code>malloc()</code> function, if your program never use <code>malloc()</code>, the formula used in <code>freeMemory()</code> will produce the wrong result. A simple corrected version for AVR that I used is here:</p>
<pre><code>extern unsigned int __heap_start;
extern char *__brkval;

int freeMemory() {
  char top_of_stack;

  if (__brkval == 0) {
    Serial.println(((int)&amp;top_of_stack - (int)&amp;__heap_start));
  } else {
    Serial.println((int)&amp;top_of_stack - (int)__brkval);
  }
}
</code></pre>
<blockquote>
<p>explain in detail what exactly does each of the keywords F(), (PGM_P)F, PSTR, const PROGMEM.</p>
</blockquote>
<h3>PSTR(&quot;string literal&quot;)</h3>
<p>PSTR came into Arduino from part of avr-libs(a C library) defined in <a href="https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html" rel="nofollow noreferrer">avr/pgmspace.h</a>, it is actually a macro, not a function as many think it was, and is defined as:</p>
<pre><code>#define     PSTR(s)   ((const PROGMEM char *)(s))
</code></pre>
<p>It looks a little bit intimidated but it actually quite simple, it not only tell the avr-gcc that the string literal <code>s</code> should be kept in program memory (i.e. Flash memory in the case of Arduino), but allows the program to convert it into a <code>const char *s PROGMEM</code> variable so that it can be pass around into some PROGMEM-aware functions as a parameter.</p>
<pre><code> //this is a PROGMEM-aware function in c
 printMsg_P(const char* str) {
     char buf[strlen_P(str)+1];
     strcpy_P(buf, str);
     puts(buf);
 }

 // this handle the normal string array function
 printMsg(const char* str) {
     puts(str);
 }
</code></pre>
<h3>F(&quot;string literal&quot;)</h3>
<p><code>F()</code> is also a macro but it is not part of the <code>avr/progmem.h</code>, it is actually part of the String class defined in <a href="https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/WString.h#L37-L38" rel="nofollow noreferrer">WString.h</a> together with a definition of a class called <code>__FlashStringHelper</code>:</p>
<pre><code>class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast&lt;const __FlashStringHelper *&gt;(PSTR(string_literal)))
</code></pre>
<p>To understand the <code>F()</code> macro and the difference between <code>F()</code> and <code>PSTR()</code> take a little bit explanation.</p>
<p>As you can see from the definition of <code>F()</code>, it casts a string literal into a <code>const char*</code> variable using <code>PSTR()</code>, and then re-cast it into a class <code>__FlashStrngHelper</code>. If you further looks at the <code>__FlashStringHelper</code>, it is actually an empty class without any construct or method, it is literally empty, so why is this useful? and why can't just pass the string literal around by just using <code>PSTR()</code>.</p>
<p>This has to do with C++'s function overload. Function overload is a feature of C++ where multiple methods could have the same function name but each with different parameters. Within all the <code>Serial.print()</code> methods, there is a method <code>Serial.print(const char* str)</code> that will take in a string literal and print it to serial monitor, but it is not PROGMEM-aware, if you pass in a PROGMEM string literal <code>Serial.print(PSTR(&quot;string literal&quot;));</code>, the same method will accept what you pass in because it meet the type checking (remember <code>PSTR</code> is actually <code>const char*</code>), but it will not print out the correct string for <code>PSTR(&quot;string literal&quot;)</code> because it simply expecting a normal string.</p>
<p>In c, as we see before, we solves the problem by using two functions with different names for handling normal string and PROGMEM string, but <code>Serial</code> is a C++ class, it needs another function overloaded method to be PROGMEM-aware, and PSTR() is clearly not the solution as we just mentioned.</p>
<p>What WSting.h and Print.cpp did is to create an overload method that is PROGMEM-aware by accepting a class as parameter, so that you can pass a <code>F()</code> wrapped string literal which has a data type of class <code>__FlashStringHelper</code> into the <code>Serial.print()</code> and get the print out correctly from program memory. See the <a href="https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Print.cpp#L44-#L55" rel="nofollow noreferrer">source code</a> yourself.</p>
<pre><code>Serial.print(const __FlashStringHelper *ifsh)
</code></pre>
<p>So in summary, the <code>F()</code> and <code>PSTR()</code> are alike, both telling the compiler to keep the string literal in the program memory, and allow the string literal to be pass around into some function as parameter. But it was designed for different purpose from different programming paradigm (C versus C++). <code>F()</code> is <code>Serail.print()</code>-friendly, while <code>PSTR()</code> is not. If you are getting <code>PSTR()</code> in a function and yet you want to send it to <code>Serial.print()</code>, you will have to explicitly cast it into <code>__FlashStringHelper</code> like this:</p>
<pre><code>Serial.print((__FlashStringHelper*)PSTR(&quot;test&quot;));
</code></pre>
<h3>PGM_P</h3>
<p><code>PGM_P</code> is a macro defined as:</p>
<pre><code>#define     PGM_P   const char *
</code></pre>
<p>Whether you want to use <code>PGM_P</code> or <code>const char *</code> is a personal preference, for example, this is copy from <a href="https://www.arduino.cc/reference/en/language/variables/utilities/progmem/" rel="nofollow noreferrer">https://www.arduino.cc/reference/en/language/variables/utilities/progmem/</a>:</p>
<pre><code>const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};
</code></pre>
<p>can be written as:</p>
<pre><code>PGM_P const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};
</code></pre>
<p>This is a lengthy explanation, but I hope this will help on better understand the subject and therefore be able to use the PROGMEM and all the associated macros effectively.</p>
