This is a typesafe way of building APIs, without exposing the internals of a type (which are implementation details).
typedef struct _cl_context* cl_context;
Doing this allows you to define the API using the type cl_context, without defining the struct _cl_context anywhere in the header files. It is clear to all that the functions take this type (a pointer) as an argument, but the user is not burdened with the details of struct _cl_context. The struct can be defined elsewhere (in the .c file or a private header).
The other approach you mention is:
typedef void* cl_context;
This is used as well many places. But requires typecasting in the code all over the place, before the argument can be interpreted. And it is not typesafe. The user can pass in any pointer as the argument, and the compiler will accept it - which is not a good thing. using the real type ensures some safety in terms of arguments being passed back and forth.