A codeunit is a container for "chunks" of C/AL code to be run "inline" or called from other objects. These "chunks" of code are properly called Functions. Since we said earlier that you could use a Report object as a container for code segments (i.e. functions), why do we need codeunits? One reason is that early in the life of C/SIDE, only codeunits could be used in this way. Somewhere along the line, the C/SIDE developers decided to relax that particular constraint, but from a system-design point of view, there are still very good reasons to use codeunits rather than other objects for function containers.
One important reason is that the license specifically limits access to the C/AL code within codeunits differently than that within reports. The C/AL code within a report can be accessed with a "lower level" license than is required to access the C/AL code in a codeunit. If your customer has license rights to the Report Designer, they can access C/AL code within Report objects. A large percentage of installations have Report Designer license privileges. But they cannot access C/AL code within codeunit objects unless they have access to a more expensive license with Developer privileges (i.e. Application Builder or Solution Developer).
Another reason is that the codeunits are better suited structurally to contain only functions. Even though functions could be placed in other object types, the other objects types have superstructures that relate to their designed primary use for forms, reports, etc. Use of such an object primarily as a repository for functions, designed to be called from other objects creates code that is often more difficult to interpret, use, and maintain.
Codeunits act only as a container for C/AL coded functions. They have no auxiliary functions, no method of user interaction, no predefined processing or predefined anything. If you are creating one or two functions that are closely related to the primary activity of a particular report, but are needed both from within and outside of the report, then, by all means, include the functions in the report. But otherwise, use a Codeunit.
There are several codeunits, delivered as part of the standard NAV product, which are really function libraries. These codeunits consist totally of utility routines, generally organized on some functional basis (e.g. associated with Dimensions or with some aspect of Manufacturing or some aspect of Warehouse management). Some developers create their own libraries of favorite special functions and include such a "function library" codeunit in systems on which they work.