 <p>I think of file descriptors as (indirect, higher-level) <em>pointers</em> to opaque file objects maintained by the kernel.</p> <p>Normally, when you deal with objects maintained by a library, you pass to the library pointers to objects that you're not supposed to dereference and manipulate yourself.</p> <p>For kernel objects, this it's not just that you're not supposed to manipulate them yourself -- you literally can't because they live in a different address space that's not at all accessible to you. And because they live in a different address space, pointers wouldn't be a meaningful way of referring to them.</p> <p>You need a token or handle which the kernel would internally resolve to a pointer that's meaningful in the kernel address space. File descriptors are such tokens in integer form.</p> <p>For the kernel:</p> <pre><code>your_process_id + your_file_descriptor =&gt; kernels_file_object_pointer </code></pre> <p>(or an <em>EBADF</em> error if a given filedescriptor may not be resolved to a file object pointer for the given process) </p>