2

I have 3 functions in my code:

#pragma Code(".my_functions")
    int  func_A(volatile ulong *from, volatile ulong *to, ulong size) {...}
    int  func_B(uint32_t *buf_src, int size) {...}
    void func_C(int size, uint32_t *buf) {...}
#pragma Code()

In another function in this file I need to calculate the size of func_A and func_B:

int calc_size()
{
        // End address of B (== start of C) - Start address of A:
        int funcs_size = func_C - func_A; // Here the error

        // ...
}

I get the next compilation error:

error: 'void (*)(int, uint32_t *)' (aka 'void (*)(int, unsigned int *)') and 'int (*)(volatile ulong *, volatile ulong *, ulong)' (aka 'int (*)(volatile unsigned long *, volatile unsigned long *, unsigned long)') are not pointers to compatible types

NOTE: I can solve the error by casting the function pointers, e.g.:

int funcs_size = (void*)func_C - (void*)func_A; 

But the same size calculation works perfect for another functions (with also different types)..

Do you know when it is Ok to use functions pointer for such calculations and why in this specific example I get the compilation error?

Thank you for your help

Halona
  • 1,475
  • 1
  • 15
  • 26
  • 6
    `int funcs_size = func_C - func_A;` is *undefined behaviour* anyway, because pointer arithmetic is valid only between parts of the **same** object, or in the case of an array, one element past the array. Also the result of the arithmetic will be the number of units of the type being pointed to. – Weather Vane Mar 26 '19 at 17:17
  • 5
    The whole exercise is unportable for multiple reasons. Conversion of function pointer to object pointer is undefined (it usually works, but isn't guaranteed by the C standard). There's no particular guarantee that the functions are laid down in a particular order; that is compiler dependent. There's no guarantee that the empty functions won't be optimized away. I'd be curious to see the analogous code that you claim works without error. Maybe the volatility has something to do with it, but probably not. – Jonathan Leffler Mar 26 '19 at 17:17
  • 2
    Depending on the processor a function pointer is not necessarily the start address of the function code. See https://stackoverflow.com/a/11714314/10622916 – Bodo Mar 26 '19 at 17:20
  • This whole thing is just all sorts of wrong. What use-case do you have that has lead you to attempt this? – Christian Gibbons Mar 26 '19 at 17:21
  • @JonathanLeffler, As I understood, the #pragma tells the compiler to put the functions in this particular order, doesn't it? Also, the functions are not empty, I've just tried to shorten the code for the question (probably it's mesleading..) – Halona Mar 26 '19 at 17:22
  • 1
    No idea; you've not identified which compiler you're working with and pragmas are almost all compiler-specific. I don't think that's a GCC pragma; is it MSVC you're using? If you omit function code, add `...` between the braces to indicate that there is material there. Or `/* ... */`. – Jonathan Leffler Mar 26 '19 at 17:23
  • @ChristianGibbons , I cannot reveal too much, in general, I need manually to copy these functions to a specific HW memory and for this I need to know their size.. If you have any idea how can I know their size, I'd be glad to hear :) – Halona Mar 26 '19 at 17:37
  • @Halona, you cannot *copy* functions either. If you want functions to reside at specific locations in memory, then you should be relying on your linker to accomplish that. How, specifically, you would do so depends on the linker. – John Bollinger Mar 26 '19 at 18:19

2 Answers2

2

I need to calculate the size of func_A and func_B:

[...]

        // End address of B (== start of C) - Start address of A:
        int funcs_size = func_C - func_A; // Here the error

C does not have any concept of the size of a function, nor any standard way to compute anything related to such a statistic.

I get the next compilation error:

error: 'void (*)(int, uint32_t *)' (aka 'void (*)(int, unsigned int *)') and 'int (*)(volatile ulong *, volatile ulong *, ulong)' (aka 'int (*)(volatile unsigned long *, volatile unsigned long *, unsigned long)') are not pointers to compatible types

Well that's one thing wrong with your code, sort of. I'd consider it more of a red herring, though. Pointer arithmetic for object pointers is defined in terms of the size of the pointed-to type, so it is not defined for pointers to incompatible types. The type of a function pointer incorporates its return type and, if specified, the types of its parameters, so even if we imagine that your function pointers were object pointers, their types are not compatible, so the subtraction operation would not be permitted.

NOTE: I can solve the error by casting the function pointers, e.g.:

int funcs_size = (void*)func_C - (void*)func_A; 

That relies on three separate extensions implemented by your compiler:

  • converting a function pointer to an object pointer,
  • computing a difference between pointers of type void *, and
  • computing a difference between pointers to objects that are not two members of the same array or to the position immediately past the end of the array.

None of those have defined behavior as far as the standard is concerned.

But the same size calculation works perfect for another functions (with also different types)

Since we're dealing with language extensions, it's difficult to say what your compiler might or might not accept. I note, however, that different parameter types are not the same thing as incompatible parameter types, and likewise different function types are not necessarily incompatible. I speculate, therefore, that your compiler might accept the difference operation for pointers to compatible function types (as an extension).

Do you know when it is Ok to use functions pointer for such calculations

It depends on what you mean by "OK". If you are trying to write code that conforms to the language standard, then it is never ok. You may not compute a difference between function pointers. You may not convert function pointers to object pointers so as to compute a difference between those.

You may convert function pointers to integers and compute their difference, but the conversion results are implementation-defined, and it is not guaranteed that there is any integer type that can represent converted function pointers without data loss.

In any event, whether a pointer difference or an integer difference is computed, the meaning of that difference is completely unspecified. Even if we assume that we thereby compute the difference between the start address of one function and that of the other, relative to some common, linear address space, there are no guarantees whatever about how the functions are arranged in memory -- not about their relative order, not about their contiguity, not about padding or alignment, nothing.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Not guaranteed that there is any integer type . . . what about `ptrdiff_t` in `stddef.h`? Or is that only data pointers? – Neil Mar 26 '19 at 21:30
  • 1
    @NeilEdelman, `ptrdiff_t` is the type of the difference between two pointers, but it is not guaranteed to be able to represent *all* differences between pointers into the same array. On the contrary, although it is generally defined for such pointer pairs (and not for any other pointer pairs), the behavior of pointer difference is explicitly undefined if not representable by type `ptrdiff_t`. – John Bollinger Mar 27 '19 at 01:14
  • Could you index into an array not representable by `ptrdiff_t`? – Neil Mar 27 '19 at 20:23
  • 1
    Of course, @NeilEdelman. And you might even be able to access the *last* element by indexing the array's identifier suitably. There are *no requirements* on the size of `ptrdiff_t` -- it could be an alias of `signed char`, or maybe even `_Bool` in a perverse, but conforming, implementation. There is also neither an absolute nor a parametric upper bound on the size of arrays that may be supported, and you are permitted to index an array with values of any integer type. – John Bollinger Mar 27 '19 at 20:51
0

I need to calculate the size of func_A and func_B

You may want to reassess that need, or edit your question to provide some justification here if you want more-useful answers.

Do you know when it is Ok to use functions pointer for such calculations

In the absence of any indication of what platform you're using we must assume you're talking about the C Abstract Machine, and in that case it is never OK.

and why in this specific example I get the compilation error?

Because the compiler is in this instance following the standard and also helpfully informing you of that.

mlp
  • 809
  • 7
  • 21