The standard C library provides an API to perform name resolution: getaddrinfo(), formerly gethostbyname(). However, for DNS resolution as well as implementation in the libc, this interface is very impractical, to the point of being unusable. Here are a few reasons why.
I explained this point in a message to the Busybox mailing-list. You can read the post here. (There is a mistake in that post about /etc/nsswitch.conf and /etc/host.conf syntax; the following two messages in the thread correct that mistake.)
TLDR: depending on the machine configuration, it is possible that getaddrinfo() will not use DNS at all.
DNS resolution performs network I/O, which can take a non-negligible amount of time. getaddrinfo() is a blocking call and there is no way to specify a timeout to make it return early, so it may block indefinitely. This is bad design.
Also, network operations being asynchronous by nature, even a synchronous API should provide a way to perform several queries at once and return when one of them, or all of them, get an answer. getaddrinfo() does not even offer that.
Because it's generic, getaddrinfo() is cumbersome to use. The data structures are impractical, requiring the user to fill in information that is irrelevant to DNS resolution. The details of the network transport protocols are of no interest to the user who just wants answers to his DNS queries!
But at the same time, getaddrinfo() does not allow the user to provide the details he wants or refine his search. It's a very basic and monolithic entry point, with no DNS-specific knobs. For instance, only A and AAAA queries are supported, which is clearly insufficient.
getaddrinfo() is a toy interface. For any half-serious DNS work, another API must be used.
Most people who need a real DNS client library use BIND's libresolv. This page explains what is wrong with it, and what s6-dns tries to do better.