C static keyword vs C++ private scope?
Asked Answered
W

1

-2

What is the C++ equvalent for translation unit local static function in C?
For example having the following in bar.c:

static void bar() {
    // ...
}

In C++, would this be written as a a private member function like

class foo {
    void bar();
};

void foo::bar() {
    // ...
}

A private member function implicitly introduces the this pointer as parameter, so it's not really comparable to the C style static function. But even a private static member function bar() would be seen in the public interface (and staying accessible for the linker), and isn't comparable as well.

While accessible scope of those functions seems to be similar, these options don't look like good replacements for the mentioned C style static function syntax.

Is the equivalent a function in an unnamed namespace, that's visible to the current translation unit only?

namespace {
    void bar() {
       // ...
    }
}
Wendt answered 24/3, 2015 at 3:45 Comment(10)
The namespace is better; it doesn't introduce an extraneous type.Altdorfer
Why must you replace it? static functions are a valid construct in C++ as well.Stonechat
@Stonechat There's different semantics in c and c++, did you notice this?Urn
Downvoters simply don't understand what's the question is all about. That's OK.Urn
Is is difficult to understand whether the question is asking a question of fact or a question of preference.Thereat
@DietrichEpp No, It's all about facts, not opinions (as the mentioned question referred to did).Urn
I am not claiming that this question is asking for opinions, I'm merely saying that it seems like it might be.Thereat
@DietrichEpp That's why I clarified :) ... I'd appreciate any edits, making it clearer!Urn
I've attempted to incorporate these clarifications into the body of the question itself. Feel free to roll back these changes if you feel that the changed question does not reflect your intent.Thereat
@DietrichEpp Your edits are completely fine. Disjunction from the initiating question included.Urn
H
10

[C] Static function with file scope.

static void bar() { ... }

This will create a function named bar that has internal linkage.

[C++] Static function with file scope

static void bar() { ... }

This will create a function named bar that has internal linkage.

[C++] Unnamed namespace

namespace {
    void bar() { ... }
}

This will create a function named bar that has internal linkage.

Conclusions

They are all identical. I'd probably recommend using the unnamed namespace in C++, because it gets rid of some of the overloading of the static keyword. But from the perspective of what your code does, it doesn't matter.

Sidebar: What does internal linkage mean?

In C and C++, we have three kinds of linkage: External, Internal and No linkage. To define these, I'm going to quote from C++ 2011 Section 3.5 Paragraph 2:

A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:

  • When a name has external linkage , the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
  • When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.
  • When a name has no linkage , the entity it denotes cannot be referred to by names from other scopes.

C 2011 has similar language at Section 6.2.2 Paragraph 2:

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

So names that have internal linkage are only visible in the translation unit that they were found in.

Sidebar: Let's include an example of how internal linkage works in practice:

Let's create 2 c++ files. bar.cc will contain just a function with internal linkage:

static void bar() {}

We'll also create main.cc, which will try to use that bar().

extern void bar();

int main() {
    bar();
}

If we compile this, our linker will complain. there is no function named bar that we can find from the main.cc translation unit. This is the expected behavior of internal linkage.

Undefined symbols for architecture x86_64:
  "bar()", referenced from:
      _main in main-c16bef.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Horsefly answered 24/3, 2015 at 4:22 Comment(18)
"They are all identical." AFAIK in the c++ case the static void bar() { ... } will still be accessible by the linker from other translation units vs. the namespace { void bar() { ... } } version. I've seen bad errors and weird behaviors about this in practice.Urn
@πάνταῥεῖ: A non-member function with static is invisible outside the source file it is defined in. A static member function is visible (if it is public) and can be used without a variable of the class type.Altdorfer
@πάνταῥεῖ: C 2011 6.2.2 doesn't really agree with you.Horsefly
@JonathanLeffler static void bar() { ... } still allows to bind it with extern in c++, as mentioned seen horses puking about it!Urn
@πάνταῥεῖ Can you provide an example?Horsefly
@πάνταῥεῖ: Here's a quote from C++ 2011 Section 3.5: External Linkage: When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit. Internal Linkage: When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.Horsefly
@BillLynch Well, you can simply try if the linker resolves static void bar() {} referenced explicitly from a different TU as extern void bar(); with the c++ compiler.Urn
@πάνταῥεῖ: Please provide an actual example that can be tossed at an actual compiler that describes what you are talking about: gist.github.com/sharth/dc1f30b3918175e7683fHorsefly
@πάνταῥεῖ: I've just tried that: bar.cpp contained: static void bar() {}, while foo.cpp contained: extern void bar(); int main() { bar(); }. The source files compile to object files OK with no warnings enabled; linking the two object files gives me errors: Undefined symbols for architecture x86_64: "bar()", referenced from: _main in foo.o and ld: symbol(s) not found for architecture x86_64. QED? (Add much in the way of warnings and the compiler complains that bar() is defined but not used.)Altdorfer
@JonathanLeffler @BillLynch Well, I have to admit I'm no longer sure about the static keyword was actually present for those bad samples I had in mind. Could well be it still preserves module private for c and c++ the same way.Urn
@πάνταῥεῖ: The word "module" is not found in C++ 2011 or C 2011. So I'm going to feel confident in saying that I don't know what "module private" is.Horsefly
@πάνταῥεῖ: It's easy to verify yourself by examining the object code. Here is an example: gist.github.com/depp/22a71901c9dc515f6377Thereat
@BillLynch "The word "module" " I'm talking about translation units of course, and stuff visible to these exclusively.Urn
Note that a static member function does not have internal linkage (actually, can't have internal linkage). Example: #include <iostream> class foo { public: static void bar(); }; static void foo::bar() { std::cout << "bar\n"; } int main() { std::cout << "main-1\n"; foo::bar(); std::cout << "main-2\n"; }. As shown, with static void foo::bar() { … }, it does not compile: error: cannot declare member function ‘static void foo::bar()’ to have static linkage [-fpermissive]. Drop that static and it compiles and runs OK.Altdorfer
@πάνταῥεῖ: I don't mean to be rude in my responses... But I honestly didn't (and still mostly don't) know what you mean when you use terms that I'm unfamiliar with, are not found in the specification, and are also not readily found on google. The term module is an especially poor choice because it may have a meaning in the future: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4047.pdfHorsefly
@JonathanLeffler: I thought that a static member function could have internal linkage if it were contained in a class defined in an anonymous namespace.Thereat
@BillLynch I didn't found you being rude anyway. What I meant with module private is certainly accomplished with the unnamed namespace approach, which guarantees the code is hidden for the linker, when trying to access it from a different module (TU).Urn
@DietrichEpp: If the class is defined within an anonymous namespace, everything about the class is hidden — no external linkage. However, the point I was trying to make, which would apply to a static member function of a class defined within an anonymous namespace as well as to the case I demonstrated, is that you declare the function with the static keyword in the class definition, but you define the function without the keyword static (and the keyword static is not allowed in the definition unless it is an inline function defined in the body of the class definition).Altdorfer

© 2022 - 2024 — McMap. All rights reserved.