Yes, well you can do a similar thing in the IDE:
inline void serialWrB(uint8_t dat)
{
UDR0=dat;
while ( !( UCSR0A & (1<<UDRE0)) ) {} //wait for byte to transmit
}
void StringPgmln(char * str){
do
{
serialWrB(pgm_read_byte_near(str));
} while(pgm_read_byte_near(++str));
serialWrB('\n');
}
int main (void)
{
UBRR0H=0;
UBRR0L=207;//These values assume double speed is enabled (see below) and a 16mhz clock is used 3 = 0.5M 2M baud rate = 0 7 = 250k 16 = 115.2k 207 is 9600 baud rate
UCSR0A|=2;//double speed aysnc
UCSR0B = (1<<RXEN0)|(1<<TXEN0);//Enable receiver and transmitter
UCSR0C=6;//async 1 stop bit 8bit char no parity bits
StringPgmln(PSTR("Hello world"));
while(1){}
}
Binary sketch size: 256 bytes (of a 32,256 byte maximum)
But by using "main" rather than setup/loop you are discarding the initialization that the libraries do for you, like setting up millis, the timers, the PWM outputs, etc.
Plus, your code has a hard-coded baud rate in it. Now of course you often want a hard-coded baud rate so that isn't too bad, but the supplied libraries work with a variable baud rate (as do digitalWrite with variables for pin numbers). So it isn't directly comparing apples with apples.
For a fair test, to prove that the libraries are "bloated" in the sense that they could have been written better, you need to compare with something that does the same thing.
I would like to point out that another advantage for the code compiled with avr-gcc vs the arduino Serial library is the string is stored in flash memory instead of ram.
It is a well-known technique that you can write:
Serial.println(F("Hello World"));
... in order to keep the string in flash memory.
A more direct comparison is probably:
int main (void)
{
UBRR0H=0;
UBRR0L=207;//These values assume double speed is enabled (see below) and a 16mhz clock is used 3 = 0.5M 2M baud rate = 0 7 = 250k 16 = 115.2k 207 is 9600 baud rate
UCSR0A|=2;//double speed aysnc
UCSR0B = (1<<RXEN0)|(1<<TXEN0);//Enable receiver and transmitter
UCSR0C=6;//async 1 stop bit 8bit char no parity bits
Serial.println(F("Hello World"));
while(1){}
}
OK, this uses your hard-coded baud rate, but the library println. And it does indeed use a lot of flash:
Binary sketch size: 1,248 bytes (of a 32,256 byte maximum)
An investigation reveals that the reason basically is that the whole Serial class is linked in (ie. Serial.available, Serial.peek, Serial.write, Serial.println etc.). Why, I'm not sure as usually the linker discards functions that are not called.
Also the generated code to handle incoming and outgoing serial interrupts is present. In practice, other than a simple example, you would probably need that. After all you usually need an interrupt handler for incoming serial, and one for outgoing serial. Your "small" example doesn't use those so it isn't really a proper test.
Put it another way: In a simple demo, which does nothing useful, you can produce smaller code. But that is exactly when you don't need it! A larger example, that handles interrupts, queuing output, timers, elapsed time, etc., your small examples are going to grow somewhat larger, approaching the size that the library-generated code is in the first place.