2

Suppose I have two different functions(C), the only difference between them is that some of their arguments are of different datatypes(I'm thinking about CBLAS right now). For example:

void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
             const int K, const double alpha, const double *A,
             const int lda, const double *B, const int ldb,
             const double beta, double *C, const int ldc);


void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
             const int K, const float alpha, const float *A,
             const int lda, const float *B, const int ldb,
             const float beta, float *C, const int ldc);

Instead of having this function defined twice, just with some datatypes different, Is there a smarter way to have these two functions? like a compiler directive or something?

EDIT(Not sure if this question is allowed by stackoverflow): I'm thinking about how these functions look after being compiled.Am I right in thinking this? "Since single precision addition and double precision addition are different instructions in the hardware level, even if the C compiler was modified to allow the kind of functions the question talks about, the final binaries would be similar because we would need to have two different functions in the binary too?"

jck
  • 1,910
  • 4
  • 18
  • 25
  • 3
    Maybe you want to switch to C++, and enjoy overloading... (meaning you can't do this with pure C) – Macmade Dec 01 '11 at 00:16
  • 1
    in C++ they can coexist with no problems. – karlphillip Dec 01 '11 at 00:16
  • c++ - function overloading - THIS WAY! :) – ScarletAmaranth Dec 01 '11 at 00:19
  • I don't think he meant what Macmade and Karlphillip understood, he knows about overloading and doesn't want to do it, he wants to write code only ones, perhaps you should go to C++ and use `template` functions :) – Tamer Shlash Dec 01 '11 at 00:20
  • @Macmade: Your edit substantially changed the question (by giving both functions identical names, while the originals differed), so I rolled it back. – Jim Lewis Dec 01 '11 at 00:20
  • C1x (should I say C11?) has type-generic expressions, but I don't think they are yet at a compiler near you. – ninjalj Dec 01 '11 at 00:21
  • @Jim Lewis Yep, you're perfectly right... Just read the question again, and noticed my mistake... Thanks for the rollback! : ) – Macmade Dec 01 '11 at 00:23
  • possible duplicate of [function overloading in C](http://stackoverflow.com/questions/479207/function-overloading-in-c) – hugomg Dec 01 '11 at 00:24
  • Besides - I would argue that function overloading is Evil. Not as evil as operator overloading, but evil nonetheless. – paulsm4 Dec 01 '11 at 00:25
  • @paulsm4 That's not the point here. And overloading is actually a killer feature, even if it can lead to some mistakes with un-experienced programmers (if you want to argue). – Macmade Dec 01 '11 at 00:26
  • Ah, now I see. Yes, you could do something with the preprocessor, but it would mess badly with your editor's syntax highlighting. :) – ninjalj Dec 01 '11 at 00:28
  • Added an additional question, if you guys are interested in discussing about that :) – jck Dec 01 '11 at 00:36
  • @jck: as for your new question: yes, this is not Java generics, in C++ templates get instantiated, in C type-generic expressions get evaluated at compile-time generating the approppriate code for the type. – ninjalj Dec 01 '11 at 00:45

3 Answers3

4

No, that is not possible. In C, every function name corresponds to one globally unique function. This is why C libraries, including the standard library, are full of function variants ending in f/l/ul/ull etc.

This limitation was recognised in the design of C++, which includes overload resolution; however, this is a rather complex process, which among other things, manifests in the fact that C++ has no universal ABI, unlike C does in practice. Thus universal libraries still conform to the C interface (and extern "C" functions in C++ cannot have overloads).

C is a simple language, simple to implement, and this means that not everything about it is comfortable.

Update: Consider for example run-time linking à la dlsym() or GetProcAddress(). Those work entirely by name, courtesy of the simple C ABI. Dynamic linking (or just linking, for that matter) isn't part of the C standard, nonetheless this is an immensely useful tool, which would not play well with overloading.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • +1 My comment is completely off-topic, but I have to say I always enjoy reading your answers... – Macmade Dec 01 '11 at 00:27
  • @Macmade: Thank you, much appreciated :-) – Kerrek SB Dec 01 '11 at 00:35
  • @KerrekSB: C1x has type-generic expressions. C99 has type-generic macros for the math library to avoid the `f/l/d` suffixes. – ninjalj Dec 01 '11 at 00:39
  • @KerrekSB: kind of. I think you need either type-generic expressions or `typeof` to implement `tgmath.h`, so you could say it's a relatively minor extension to the compiler or preprocessor. – ninjalj Dec 01 '11 at 00:48
  • @ninjalj: Right. I suppose you can use the preprocessor to make lots of things easier to *write*, but if you wanted, say, to write an export library, you'd still be limited to one function per name -- is that true even for C99/1x? – Kerrek SB Dec 01 '11 at 00:51
  • @KerrekSB: well, libraries are outside the scope of the C standard. Anyway, I think you also have to do some dirty things to `dlsym` a C++ symbol, don't you? – ninjalj Dec 01 '11 at 00:58
  • @ninjalj: Of course -- you cannot :-) Not in a portable way, that is. The only proper way is to use `extern "C"`, which means you're limiting yourself to the C interface (i.e. no overloads). – Kerrek SB Dec 01 '11 at 01:10
0

<Hideous monstruosity>:

#define cblass_gemm(type_prefix, type) void cblass_##type_prefix##gemm(       \
            const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,  \
            const enum CBLAS_TRANSPOSE TransB, const int M, const int N,      \
            const int K, const type alpha, const type *A,                     \
            const int lda, const type *B, const int ldb,                      \
            const type beta, type *C, const int ldc)                          \
{                                                                             \
    type var;                                                                 \
}

cblass_gemm(d,double)
cblass_gemm(s,float)

That beast begets:

$ gcc -E blass.c
# 1 "blass.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "blass.c"
# 11 "blass.c"
void cblass_dgemm( const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const double alpha, const double *A, const int lda, const double *B, const int ldb, const double beta, double *C, const int ldc) { double var; }
void cblass_sgemm( const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const float alpha, const float *A, const int lda, const float *B, const int ldb, const float beta, float *C, const int ldc) { float var; }

Of course, your editor's syntax highlighting has just become less than useful.

ninjalj
  • 42,493
  • 9
  • 106
  • 148
0

As the comments have pointed out, there is no function overloading in C, which is perhaps A Good Thing. But I have a suggestion. Suppose we have:

void foo(double *);

Then of course we can't compile the following fragment:

float f;
foo(&f);

A possible solution is wrap foo() in a macro of the same name:

#define foo(p) do {        \
   double _ = *(p);        \
   foo(&_);                \
   *(p) = _; } while(0)

Then both foo(&f); and double d; foo(&d); will compile.

Some notes:

  • The do {...} while (0) code is to 'swallow semi-colons'.

  • This macro needs a name for its temporary double; I've chosen _. This will hopefully avoid gcc's 'shadow' warnings. An alternative is to use a_very_long_name.

  • This has 'macro semantics', and so the (unlikely) double *d; foo(d++); would not work. But if this is possible in your environment, you should follow convention, and name the macro FOO rather than foo.

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77