Why can’t I use this C function – it is there but I cannot see it.

I’ve been writing in C for over 20 years, and it is humbling when you suddenly realise how little you know of a topic.
It reminds me of when I worked for IBM, and the company wanted a skills register. The questions were along the lines of

Rate your skills in the following areas from 0 (nothing) to 10 (expert).

  • z/OS
  • DB2
  • CICS
  • etc

Overall the skills register was found to be not useful, as the rankings were inverted. If someone put themselves down as 10 – it usually meant they knew very little, they knew enough for their day to day work. If someone put themselves down as 2 they may be an expert who realises how much they do not know, or someone who honestly realises they do not know very much.

My humbling discovery was that when I ported some existing C code to run on z/OS, the functions were not visible outside of the C program. There were two reasons for this.

  • The functions were defined as static,
  • The functions were not exported.

Static functions

static int hidden(int  i)
  return 0;
int visible(int i)
  int x = hidden(1);
  return 0; 

I think that using “static” in this case is the wrong word. It does not mean static. I think “internal” would be a clearer description, but I do not think that I’ll have any success changing the C language to use “internal”.

The function “hidden” can only be used within the compiled unit. It cannot be referenced from outside of the compiled object. The “visible” function can use the “hidden” function as the code shows.
The function”visible” is potentially visible to external programs. You can load the module and execute the function.

Exported functions

You have to tell the compiler to externalise functions within the compile unit.

For example

#pragma export(COLIN)
int COLIN(char * self, int args) {
   return 8;

or the compiler option EXPORTALL for example


What has been exported?

When you bind (linkedit) your program, the binder and report the exported functions. You need the binder parameters XREF and DYNAM=DLL

This gave output like

IMPORT/EXPORT     TYPE    SYMBOL              DLL                 DDNAME   SEQ  MEMBER 
-------------     ------  ----------------    ----------------    -------- ---  --------- 
   IMPORT         CODE64  __a2e_l             CELQV003            CELQS003  01  CELQS003 
   IMPORT         CODE64  malloc              CELQV003            CELQS003  01  CELQS003 
   IMPORT         CODE64  CSQB3BAK            CSQBLB16            MQ        01  CSQBMQ2X 
   EXPORT         DATA64  ascii_tab 
   EXPORT         CODE64  printHex 
   EXPORT         CODE64  COLIN 

This shows the imported symbols, and where they came from, and what was exported.

  • ascii_tab is a table of data in 64 bit mode
  • printHex is a function in 64 bit mode
  • COLIN is a function in 64 bit mode.

How to use it.

You can use handle= dlopen(name,mode) to get the load module into storage, and functionPointer=dlsym(handle,”COLIN”) to locate the external symbol COLIN in the load module.

Why is a static function useful?

With Python external functions (written in C), it uses static functions to hide internals. For example

static PyObject * pymqe_MQCONN(
... )
static struct PyMethodDef pymqe_methods[] = { 
  {"MQCONN", (PyCFunction)pymqe_MQCONN,... }, 
  {"MQCONNX", (PyCFunction)pymqe_MQCONNX,... },

When the external function is imported, the initialisation routine returns the pymqe_methods data to Python.

Python now knows what functions the module provides (MQCONN, MQCONNX), and the C code to be executed when the function is executed.

This means that you cannot load the module, and accidentally try to use the function pymqe_MQCONN; which I thought was good defensive programming.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s