Most of the built-in types in Python have associated type-check functions, which you can look up in the docs. For example, PyLong_Check checks whether an object is an int (accepting subclasses), and PyLong_CheckExact does the same check, but rejecting subclasses:
if (PyLong_Check(whatever)) {
// do int stuff
}
There are also C-level equivalents of type and isinstance.
To access an object's type in C, you can use Py_TYPE(whatever). This gives you a borrowed reference to the object's type - it's equivalent to accessing the object's ob_type field. The value is of type PyTypeObject*; you can cast it to PyObject* if you need to.
Alternatively, if you need a new reference, you can use PyObject_Type(whatever). This gives you a PyObject*; you can cast it to a PyTypeObject* if you need to. (The difference in pointer types has nothing to do with the difference in reference count handling.)
There are two ways to do isinstance at C level, depending on what you actually want. The first is PyObject_IsInstance(whatever, WhateverClass), which is exactly equivalent to isinstance, including handling virtual subclasses and false __class__ attributes the way isinstance does, and handling tuples of classes as the second argument. This is often not what you really want at C level, since passing a PyObject_IsInstance test guarantees nothing about an object's memory layout.
The second is PyObject_TypeCheck(whatever, WhateverClass), which requires that whatever is a "concrete" instance of WhateverClass - the actual type of whatever has to either be WhateverClass or a "real" descendant of WhateverClass. This ensures that whatever has the actual C-level members an instance of WhateverClass is expected to have.
For example, with the following classes:
import abc
class A(metaclass=abc.ABCMeta):
pass
class B: pass
A.register(B)
class C:
__class__ = int
b = B()
c = C()
PyObject_IsInstance(b, A) and PyObject_IsInstance(c, int) would both be true, but PyObject_TypeCheck(b, A) and PyObject_TypeCheck(c, int) would be false.
Type-specific type-check macros like PyLong_Check behave like PyObject_TypeCheck, not PyObject_IsInstance. They ignore virtual subclasses and false __class__ attributes.