-2

I want to check the detail of the function sem_post() in semaphore header file,which is below

extern int sem_post (sem_t *__sem) __THROWNL __nonnull ((1));

And then I find the sem_post.c file in source code of glibc, but in this file, the function's name is __new_sem_post().

I know it's about CRT, but I don't know how. So, there are questions:

  1. Why there is an "extern" and how it work?
  2. How does the name change from __new_sem_post() to sem_post()?
Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
Ether
  • 9
  • 1
  • "How does the name change" by compiler and linker magic (also known as "language extension") that allow one to create verioned symbols in a library. So both `__new_sem_post` and `old_sem_post` change to `sem_post` but to different versions of it. To see them, do `nm -D /lib64/libc.so.6 | grep sem_post` (or wherever your libc.so.6 is), – n. m. could be an AI Jul 07 '23 at 14:52
  • On SO it is the practice to ask one question in one post. Your title is clearly advertising that you are contravening that norm while providing little specific information about the question. The fact that you have a question is implicit - it is a Q&A after all - and the fact that is about C is in the tag. Always best to not state what you "know", just let people tell you. Less chance of fruitless distraction if anyone chooses to challenge your assertions. – Clifford Jul 07 '23 at 17:07

2 Answers2

2

extern means that you are declaring something that is not (necessarily) defined here, but in some other units. So extern int x; doesn't allocate memory for a variable x. It just declares to the compiler that, somewhere else in this code (may be in another compilation unit, that is another .c file) that variable will be defined. That is that, somewhere else, there is a int x; declaration.

This allows the compiler to know that it should not fail if some code uses x. Instead of saying "x: symbol undefined", it will know that x is some global variable of type int, and compile any code referring to x as such.

Then, of course, at some point, it will be necessary to check that, indeed, there is such a variable. But that is done at linking stage. That is, not when you compile, separately, each .c file into a .o file. But when you put all the .o files, plus the libraries, together, to create an executable.

Understand that, mainly, this is what .h file do: they contain, no code (I mean not code that should generate assembly code), but declarations. Declarations whose purpose is to give some contextual information for the compiler when compiling your .c file.

Example

Let's consider an example case, in which you do, in a file testsin.c

extern double sin(double x);

int main(){
    printf("%f\n", sin(1.0));
}

Then compile that file with gcc -c testsin.c.
And then link the given .o and the libm library together, to create a testsin executable, using gcc -o testsin testsin.o -lm

When compiling (gcc -c) testsin the compiler doesn't have any code about a sin function, nor does it have any reason to know what you are talking about, and where this sin function is. Later, when linking (gcc -o testsin testsin.o -lm) you'll provide the library that contains the sin function (libm.so, here passed with -lm). But that is later. Without any DeLorean, it can't guess at compile time (gcc -c) what this sin thing is. So you must tell it "don't worry, don't raise an error, I swear this function exists, with this signature, and I will provide it to you later".

This, in C language, is said by the declaration extern double sin(double);

Now, of course, more realistically, what you would do is not that, but

#include <math.h>

int main(){
    printf("%f\n", sin(1.0));
}

But that is the exact same thing. As its name suggest #include just "copy&paste" the content of math.h in your code. And math.h just contains some such declaration as extern double sin(double);.

implicit extern

And I kept main information for the end, since I suppose, once all that clarified, that the reason why you are surprised to see this extern, is that you have already seen some other code with simply double sin(double); to do the same declaration.

Well, yes, extern is implied for function declarations: if there is no code (no {...} containing actula code), then extern is implied any way.

It is for variables that you must always say it explicitly, because int x; is the creation of the variable, not a declaration.
So, variable creation = int x;. Function creation = double sin(double x){...}
Variable declaration = extern int x;. Function declaration = extern double sin(double x); OR double sin(double); since that is unambiguous in this case.

As for your second question, I don't know (and anyway, rule around here is that you are supposed to ask a single question). But it is quite usual to have some "private" implementation of functions, in internal code, for example specific to an architecture, named with some _, and then, in some other places, a simple alias to make somefunc point to __someprefix_somefunc_somesuffix_ or thing like that.

chrslg
  • 9,023
  • 5
  • 17
  • 31
1

I want to check the detail of the function sem_post() in semaphore header file,

This is probably a mistake. Header files are primarily intended for machine, not human, consumption. They are often difficult to follow, especially those of the standard library. Read human-oriented documentation instead. For example, manual pages.

which is below

extern int sem_post (sem_t *__sem) __THROWNL __nonnull ((1));

And then I find the sem_post.c file in source code of glibc, but in this file, the function's name is __new_sem_post().

Well, no. You found source for a function that appears to be named __new_sem_post. From its name and context, this function is undoubtedly related to sem_post, but if that's really its name (see below) then it is a separate function.

I know it's about CRT

Aside: other than in Microsoft-land, "C runtime library" is an uncommon phrase, and its initialization as "CRT" even more so. The "[C] standard library" is more conventional, especially when you're talking about its specifications, as opposed to its expression as executable code.

  1. Why there is an "extern" and how it work?

Because somebody was being pedantic. extern declares that the function has external linkage, meaning that any function in any source file can call that function via its name. The alternative is internal linkage, which means that the specified name identifies the function only to other functions in the same source file / translation unit. But extern is the default for function declarations, so it is rarely declared explicitly for functions (variables are a different story).

  1. How does the name change from __new_sem_post() to sem_post()?

It doesn't.

Now, it's possible that there is some preprocessor magic being applied that makes you think there is a function named __new_sem_post, when its name is really sem_post. Perhaps you would be inclined to describe that as a name change, but it's not.

It's also possible that there is a separate sem_post function that you overlooked. Either way, functions have the names they are defined with. C does not define any mechanism by which these could change.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157