0

I need two instances of the same function (not just alias). One thing that definitely works is

void writedata(union chip *tempchip, unsigned char *datapos, int datanum)
{
   blahblah
}

void writestring(union chip *tempchip, unsigned char *datapos, int datanum)
{
   writedata(tempchip, datapos, datanum);
}

This is kind of silly, because the second just passes parameters to the first. So I tried to be "smart" and make a pointer

void writedata(union chip *tempchip, unsigned char *datapos, int datanum)
{
   blahblah
}

void (* writestring)(union chip *, unsigned char *, int) = writedata;

which on using returns segmentation error. Why is the second method not working?

EDIT: I am calling both functions from Python via ctypes:

writedata = parallel.writedata
writedata.argtypes = [devpointer, POINTER(c_ubyte), c_int]

writestring = parallel.writestring
writestring.argtypes = [devpointer, c_char_p, c_int]

because I want to supply both strings and byte arrays as the second argument.

Pygmalion
  • 785
  • 2
  • 8
  • 24
  • 1
    looks okay, can you give a full example? – mch Nov 13 '20 at 08:56
  • 2
    [cannot reproduce](https://ideone.com/OyRzmQ) . post a [mcve]. – WhozCraig Nov 13 '20 at 08:57
  • 1
    Are you calling it from a separate file? It needs to be declared consistently with the definition, i.e. as a function pointer, not a function. – Tom Karzes Nov 13 '20 at 09:00
  • I am calling both functions from `Python` via `ctypes`. – Pygmalion Nov 13 '20 at 09:04
  • 1
    @Pygmalion That's the problem. `ctypes` is trying to call it as a function. It needs to call it as a pointer to a function, i.e. it needs to first load the value of the pointer, then call it. `writestring` isn't really an alias for `writedata`. It's a pointer that points to it. C syntax is very flexible about it, so it can *appear* to be an alias, but it isn't. `writestring` has associated storage, for the pointer. – Tom Karzes Nov 13 '20 at 09:08
  • @TomKarzes OK so is it possible to create an alias, callable from outside, but without ridiculous passing of arguments? – Pygmalion Nov 13 '20 at 09:11
  • @Pygmalion What you really want is for your object file to define two symbols for the same function. It's a reasonable desire, but I don't know of a way to do it. It might be possible by manipulating the object file in some way, but I don't think it can be done directly from C. – Tom Karzes Nov 13 '20 at 09:13
  • @TomKarzes So my silly solution is just the best I can achieve and I should be happy with it? – Pygmalion Nov 13 '20 at 09:15
  • @Pygmalion It's certainly the simplest and most portable. Trying to alias the symbols in the object file is iffy at best. – Tom Karzes Nov 13 '20 at 09:16
  • @Pygmalion "simple and pragmatic" it not silly. – Jabberwocky Nov 13 '20 at 09:16
  • @TomKarzes IIRC, K&R had a keyword for this (entry?) – wildplasser Nov 13 '20 at 09:17
  • @wildplasser Huh, that's interesting. I don't think it was ever consistently supported. I [found this](https://stackoverflow.com/questions/254395/whatever-happened-to-the-entry-keyword) which discusses it a bit. But yeah, that's exactly what OP is looking for. – Tom Karzes Nov 13 '20 at 09:20
  • I never used it either. The communication with the linker was rather rural, those days. (underscores, etc) – wildplasser Nov 13 '20 at 09:22
  • @Pygmalion Another possiblity is to do `#define writestring writedata` in a header file, so that it ends up expanding to `writedata`. That would let you use the appropriate name in your source code while still having only one function. It just wouldn't show up in the symbol table. – Tom Karzes Nov 13 '20 at 09:22
  • @TomKarzes I tried `define` method, but `ctypes` couldn't find `writestring`. It seems that C compiler did not create `writestring` instance because it was never used. Maybe the problem is that I do not use header files at all? – Pygmalion Nov 13 '20 at 09:27
  • For clarification, do you have *one* function in C, but from Python, want to pass both byte strings (e.g. `b'test'`) and byte arrays (e.g. `(c_ubyte*8)(1,2,3)`). This seems like an XY problem that you need to describe in more detail. I ask because of this [other question of yours](https://stackoverflow.com/q/64810622/235698)... – Mark Tolonen Nov 14 '20 at 21:25
  • I've run into this problem and solved it with a few of the answer suggestions missing OS, Python Version, shell, etc. There are flags that only work in specific places, with restrictions from the os you are on. Your other question suggests this is the issue that you have not given information Mark has requested and needed to answer. – April_Nara Nov 14 '20 at 21:46
  • @MarkTolonen You got the question right. I described my problem as good as I could, but I am open to suggestions how to improve it. – Pygmalion Nov 15 '20 at 08:32

3 Answers3

2

I think there's a solution that might work for you. It achieves the effect you were after, but it does it from the linker rather than your C source.

My assumption is that you're building a shared library for use with Python. If that assumption is correct, then you can do the following.

Let's say your shared library is called libclib1.so, and that you're doing something like the following to create it:

gcc -shared mysource.o -o libclib1.so

You can change this to add an alias for your function as follows:

gcc -shared mysource.o -Xlinker -defsym=writestring=writedata -o libclib1.so

This will create a new symbol, writestring, with the same value as writedata.

Of course, if you have a bunch of these, doing this on the command line could be a problem. But there's a solution for that as well. All you need to do is create a file with all your alias options in it. For example, you could call it aliases.txt. It would look like:

-Xlinker -defsym=writestring=writedata

The file could contain as many options as you like, each on their own line. Then you can change your shared library link command to:

gcc -shared mysource.o @aliases.txt -o libclib1.so

This will pick up the options from aliases.txt, adding all of your needed aliases to libclib1.so.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
2

I think you just want to pass data different was to a single function, such as this other question you asked. The solution is to use a c_void_p on the Python side to accept different kinds of pointers. The C code will receive the pointer and treat it as unsigned char *.

Here's a sample DLL which just focuses on the problem:

test.c

#include <stdio.h>

__declspec(dllexport)
void func(unsigned char *datapos, size_t length)
{
    for(int i = 0; i < length; ++i)
        printf("%02hhx ",datapos[i]);
    printf("\n");
}

test.py

from ctypes import *

dll = CDLL('./test')
_func = dll.func
_func.argtypes = c_void_p,c_size_t
_func.restype = None

def func(data):
    _func(data,len(data))

test1 = b'\x01\x02\x03'
test2 = (c_ubyte*3)(1,2,3)

func(test1)
func(test2)

Output:

01 02 03
01 02 03
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • Fantastic. Actually very simple and logical solution, essentially bypassing `ctypes` pointer type check by specifying generic pointer. In the moment my favourite solution. – Pygmalion Nov 15 '20 at 08:26
0

Two instances of the same function: (I think the OP wanted two entry points, or labels or symbols , though)


inline static unsigned f0( unsigned aa, unsigned bb)
{
return aa %bb + bb %aa;
}

#if WANT_MAGIC /* not needed, anyway */
#define MAGIC  __attribute__ ((noinline)) 
#else
#define MAGIC  /**/
#endif

unsigned MAGIC f1( unsigned aa, unsigned bb)
{
return f0( aa, bb);
}

unsigned MAGIC f2( unsigned aa, unsigned bb)
{
return f0( aa, bb);
}

You could make the f1 and f2 functions different: accepting different argument types, and casting appropiately.

wildplasser
  • 43,142
  • 8
  • 66
  • 109