0

I'm a bit confused with a topic in the C17 standard.

In 6.2.2, point 5 you can read:

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. [...]

Meaning that it could have either internal or external linkage, depending on other declarations (if any) of that function before that one.

On the other hand, in 6.7.6.3, example 1 (points 16 and 17), you can read:

int f(void), *fip(), (*pfi)();

[...]

If the declaration occurs outside of any function, the identifiers have file scope and external linkage. [...]

So, it's ok with pfi (it's not a function, but a pointer), but what happens then to f and fip? Isn't that a contradiction? In 6.2.2, it's "as if the extern storage-class specifier was present" (which doesn't always mean it will have external linkage), but in 6.7.6.3 it seems the external linkage is given for granted.

What am I missing?

Edit: to be more specific, if we have this code in file scope:

// One random "previous declaration":
static int f(void);  // declares internal linkage
// Now, the important line, from the initial example:
int f(void);  // Internal linkage? External linkage?

6.2.2 states that the second declaration has internal linkage.

6.7.6.3 states that the second declaration has external linkage.

Lundin
  • 195,001
  • 40
  • 254
  • 396
Pep
  • 625
  • 4
  • 19
  • 1
    A function is not a variable, hence it is not stored in a variable storage area. `pfi` is a variable and so is stored in a variable storage area. `f` and `fip` are declarations of functions returning a [pointer to] `int`. – Paul Ogilvie Jun 20 '21 at 07:11
  • 1
    I don't follow you. Both quotes seem to me very clear: they both say the identifer has external linkage. – bolov Jun 20 '21 at 07:11
  • `extern` tells the compiler "it exists, but maybe not in this compilation unit." – Paul Ogilvie Jun 20 '21 at 07:14
  • @bolov not really: "as if extern was used" doesn't necessarily mean it's external: it depends on former declarations. – Pep Jun 20 '21 at 07:14
  • @PaulOgilvie it's all about identifiers that refer to either a function or an object. They are treated differently. The meaning of `extern` is clear, but the explanations seem to contradict. – Pep Jun 20 '21 at 07:17
  • @PaulOgilvie in the standard (6.2.2 and 6.7.6.3). – Pep Jun 20 '21 at 07:22
  • Can't see any contradiction. For a function declaration, both state that `extern` is implied. In other words, the function definition may be in another compilation unit. – Weather Vane Jun 20 '21 at 07:25
  • @WeatherVane `extern` doesn't always mean external linkage, according to 6.2.2, point 4. – Pep Jun 20 '21 at 07:34
  • What of it? There is still no contradiction. Point 4 says that if the linkage was already specified, you can't over-rule it. – Weather Vane Jun 20 '21 at 07:38
  • @WeatherVane that's exactly the question: 6.7.6.3 seems to state you can over-rule it, as it says its directly external, not depending on former declarations. – Pep Jun 20 '21 at 07:49
  • I still can't see a contradiction. The declarations given in point 16 do not attempt to specify `extern` and point 17 explains what will happen. – Weather Vane Jun 20 '21 at 08:06
  • 2
    Examples are not normative, may rely on unstated assumptions, may be outright incorrect etc. This example assumes this is the first declaration. – n. m. could be an AI Jun 20 '21 at 08:08
  • @WeatherVane check the edit in the question. – Pep Jun 20 '21 at 08:16
  • @n.1.8e9-where's-my-sharem. That really makes perfect sense, and gives me peace of mind. So the example is quite confusing because the explanation goes on, and says that whether the declaration is in block scope, the linkage depends on former declarations. They should have included that hint in both cases. Thanks! – Pep Jun 20 '21 at 08:19
  • It is a nit pick. The point 17 does not contradict, it just overlooks to say *subject to 6.2.2.4* if the attempted specification contradicts a previous declaration. In the question edit, the second declaration will be `static` as 6.2.2.4. – Weather Vane Jun 20 '21 at 08:20
  • @WeatherVane yep, you're right. The wording of the text is confusing, as it makes one assumption that does not make in the case of block scope. – Pep Jun 20 '21 at 08:28

1 Answers1

2

Either the example code in C 2018 6.7.6.3 16 was intended to be stand-alone code with no prior declarations or the authors of the text in C 2018 6.7.6.3 17 that says “If the declaration occurs outside of any function, the identifiers have file scope and external linkage” overlooked the fact that f could have internal linkage due to a prior declaration with static and that this new declaration would retain that prior linkage.

As noted in the question, C 2018 6.2.2 5 says “If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern…” Not noted in the question, 6.2.2 4 says “For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration…” And of course we know 6.2.2 3 tells us “If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.”

Thus, if the example code int f(void), *fip(), (*pfi)(); in a scope in which a prior file-scope static int f(void); is visible, then the f in the example code has internal linkage.

So C 2018 6.7.6.3 17 is wrong to say f necessarily has external linkage unless the example is intended to be stand-alone code with no prior declarations. Further, 6.7.6.3 17 is example text, and “In ISO standards, examples are without exception non-normative.” The other text quoted above is normative text, so it is binding and the example text in 6.7.6.3 17 is not.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312