Search code examples
cpointersmemory-addressvoid-pointers

Is there recommended way to return an address in C?


I have to get an address back from a function. I'm using a 32bit system and will be, this code does not need to be portable, however, I would consider that a benefit.

Of all the options I think these three make the most sense to a reader.

  1. Passing it around as native size_t like a uint32. There is little room for error here. So I THINK this is safe, right? You need to be explicit about re-casting it when you want to use it.
uint32_t address = 0;
example_structure_t *str;

find_address(&address);
str = (example_structure_t*) address;

  1. This does seem to be what void pointers are for. But the number of times I've been bashed in the head with "void pointers are bad" is not null. Is this unsafe in any way? Returning like this, I lose my ability to return errors other than success/failure by implying if ADDRESS is null or not.
void *address;
example_structure_t *str;

address = find_address();
str = address;
  1. Seems like a good spot for a double pointer. I have a guy that works under me and is just learning C, so I wasn't trying to confuse him just yet.
example_structure_t **str;

find_address(str);

I know there is a ton of opinion on how this can be done. But is there anything factual in terms of safety or best practice?


Solution

  • Passing it around as native size_t like a uint32. There is little room for error here. So I THINK this is safe, right? You need to be explicit about re-casting it when you want to use it.

    No, neither size_t nor uint32_t is certain to be suitable for this purpose, even on 32-bit systems. The size of an address is not necessarily the same as or smaller than the size of a machine word -- if indeed that is indeed what a uint32_t represents in a given implementation -- and there is no guarantee that it will fit in a size_t either. If you want to pass addresses around in integer form then you should use intptr_t or uintptr_t (from stdint.h). If your implementation does not define these optional types then there might not be any integer type suitable for the purpose.

    With that said, however, if you're trying to convey a pointer, then it's odd to propose conveying it other than as a pointer.

    This does seem to be what void pointers are for. But the number of times I've been bashed in the head with "void pointers are bad" is not null. Is this unsafe in any way? Returning like this, I lose my ability to return errors other than success/failure by implying if ADDRESS is null or not.

    It is what void pointers are for if there is no more suitable pointer type. If you will always be returning a pointer to a specific data type, on the other hand, then the pointer type should reflect that. There is nothing inherently unsafe with returning a pointer, target type notwithstanding.

    If you need to provide finer-grained status information than success / failure, then you should use an out parameter in addition to the function's return value. It's your choice, then, whether the pointer or the status code is conveyed via that parameter.

    I've no idea what misguided programming philosophy or coding convention might teach that use of type void * in C is unconditionally bad. There are definitely situations in which it is the right thing to do, and they're not all that rare.

    Seems like a good spot for a double pointer. I have a guy that works under me and is just learning C, so I wasn't trying to confuse him just yet.

    That would be the out parameter option already discussed. There's nothing particularly wrong with that, but if you can do without an out parameter by using the return value, then that's the way I would go, myself.

    I know there is a ton of opinion on how this can be done. But is there anything factual in terms of safety or best practice?

    I don't think there's much diversity of opinion about how it can be done. I'm disinclined to believe that many people would disagree that if you specifically want to convey a pointer then you would best do so as a pointer, or that you should prefer a more specific pointer type over void * where there is one that serves the purpose. Beyond that, I'd say the details are a matter of project convention, situation-specific requirements, and personal preference.