Arduino and USB, how it works?
On "ordinary" Arduino boards like the Uno, the AVR microcontroller's serial UART is used to communicate with a PC.

Because modern PC's no longer tend to have serial ports, the 9-pin serial connector and level translators found on the earliest Arduino boards have long since been replaced with an on-board USB&lt;>Serial bridge chip.  Originally this was an FT232R, but from the Uno it has been a different Atmel MCU such as the ATmega8u2 or 16u2 running a firmware which provides similar functionality.

Essentially, the Arduino's main processor needs to have its hardware UART configured to output debug messages or program data at a chosen baud rate, using logic level asynchronous serial signaling.   If the USB port is connected to a computer running appropriate CDC ACM drivers, the USB bridge chip will be commanded to batch the data received and forward it to the host computer, where it can be claimed from serial APIs just as if it came from a traditional serial port.

To communicate in the other direction, a program on the PC sends data through serial APIs, this is batched into USB packets and sent to the bridge chip, which turns it into asynchronous serial data and sends it to the main MCU.  A program running on the Arduino itself would need to be written to collect this data form the UART, typically using interrupts (or optionally frequent polling) and then interpret it.

The bootloader used on the Arduino performs both of these operations on its own behalf while running - briefly after each reset, longer if it sees traffic related to a bootloader.   But that capability is irrelevant to the main program (aka "sketch") which must re-implement the logic to interact with the UART itself.  Worth noting that you can use the Arduino bootloader without using the IDE or writing Arduino-style programs.

If you look around online, you'll probably find many code examples for using the ATmega UART in a C program, vs. a C++ or Arduino one.

Some other Arduino boards work differently; for example the Leonardo uses an ATmega32u4 chip as its main processor, which can directly speak USB.  In that case there is no extra bridge needed.  But instead of simple UART configuration, the program on the main MCU must now include much more complex logic for dealing with the USB hardware itself, including interrupts that must run fairly frequently.  This is much harder to implement in a from-scratch project, though it does mean a lower parts count and a little more flexibility since the USB port can be used for purposes beyond channeling a virtual serial stream.