I disagree. While it is possible, it is never easy. You are limited to exactly the features the C provides.
Pointers - better null check them even if you guarantee they won't be null. (assuming they are supported at all in the target, if not copy all the data in out)
Want to use a string - your language probably has a better string type the null terminated C string - are you going to pay the overhead to copy the string (remember to copy it back and forth for each call); or are you going to use C strings in your non-C code? Don't forget to remember the length of the buffer is different from the length of the string if you modify that string.
What to use a list - C supports arrays (which are just syntactic pointers). Nearly ever language has a better list type, which for starters encodes length.
Many languages are garbage collected, which is going to require a lot of work to make work well across the C API.
And so on.
For the above, as a C++ programmer I'm reaching for std::string and std::vector - which are both very good. I have a much better type than the C API allows, but I can't use it. Odds are your language has an equivalent that is just as good (possibly with different trade offs - those details are not the point so lets not argue it here), but since the memory layout isn't 100% the same you can't use my string/vectors directly in code as if they are the native types.
On the surface it seems easy. If you are only doing it a few times it isn't hard. However the details are hard and important and the more you mix the harder it gets since the above details (any many many more on the same lines) start to matter.