How does this even compile? Dynamic arrays? Huh?

I’m trying to understand some code that appears to work but I can’t even figure out how it compiles. I’ve been programming in C++ and C for many years and I’ve never seen this.

From the ESP8266 Example sketch WifiTelnetToSerial which does appear to actually work / run, lines 75 to about 85:

 //check UART for data
  if(Serial.available()){
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);
        delay(1);
      }
    }
  }

How does one define ‘sbuf’ as an array of ‘len’ bytes when ‘len’ is a dynamic quantity returned by Serial.available(), and not a constant known at compile time? Does Arduino or recent C++ standards implement some sort of dynamic stack variables I’ve never heard of?

https://www.google.com/search?q=gcc+variable+array+size

It works because sbuf is a local / auto (located on the stack). It's not much different than space allocated with alloca.

As far as I can remember C++ has always worked like this and it offered a lot of flexible memory management options.

"Because the number #1 factor that separates C++ programmers from hackers is memory management" Dr. Bruce Draper, CSU

    if(Serial.available()){  
       size_t len = Serial.available();   //find out how many bytes are available in the Serial  buffer
       uint8_t sbuf[len];                 //allocate that many bytes in memory as variable sbuf
       Serial.readBytes(sbuf, len);       //move len bytes from serial buffer to sbuf
       ...
    }                                     //deallocate sbuf from memory

Allocating the sbuf[len] array is no different than temporarily allocating an integer or byte. Any memory variables allocated inside the {} are only accessible to this instance of the enclosed code, override variables with the same name in a prior level, and get deallocated after the {} section. So this code will work to print 321.

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  int x = 1;
  {
    int x = 2;
    {
      int x = 3;
      Serial.print(x);
    }
    Serial.print(x);
  }
  Serial.print(x);
}

void loop() {
  // put your main code here, to run repeatedly:

}

wzaggle:
As far as I can remember C++ has always worked like this...

Nope. Just GCC.

The errors from Visual C++ 2017 (which is typically very standards compliant)...

Error (active)	E0028	expression must have a constant value	Win32Project1	Win32Project1.cpp	22	
Error	C2131	expression did not evaluate to a constant	Win32Project1	win32project1.cpp	22

I can remember using a Whitesmiths C compiler back in the 1980s which allowed variable-sized local arrays.

Must check my copy of K&R.

Thumbs up for C (standard in C99 according to the GCC documentation). Thumbs down for C++.

Thanks... Should have said C and not C++ . Wonder why VLA's never made it to C++ standards? Maybe Stroustrup didn't like them or they conflicted with C with Classes somehow. I can see where trying to allocate dynamically each time through a code block could be a possible compiler pain and create a lot of memory problems. I looked back through my Design and Evolution of C++ book but can't see that he mentions them. Should probably Google it and read the arguments.

Thanks for the replies.

I could understand how this could theoretically work, given that one could allocate on the stack at the time of the definition since for any given iteration, the length would be known at that point. I just didn't recall it being part of any C++ I had ever used.

I learned using Stroustrupp's CFront initially on the Mac (I actually wrote the MPW Object Pascal to C++ translator used by most of the major Mac developers in the early 90s when Apple discontinued Object Pascal with the move to the PowerPC chip); and Visual C++ for a decade or so, then LLVM / Clang, and then finally gcc for about the last 10 years.

This being a gcc-only extension helps me understand why I have not seen it before. Still, it does seem like something I should have seen at least once before. It jumped out at me the second I saw this code.