...
That is, if a function has an external and inline definition, implementations are free to choose which definition to invoke (two distinct invocations of the function may call different definitions, one the external definition, the other the inline definition). Therefore, issues can arise when these definitions reference internally linked objects, or mutable objects with static /or thread storage duration.
Noncompliant Code Example (Internal Linkage)
This noncompliant code example refers to a file scope static variable , which has with internal linkage , inside from within an external inline function:
...
Noncompliant Code Example (Modifiable static)
In this This noncompliant code example , we have includes two translation units, : file1.c and file2.c. The first file, file1.c, defines a random number generation function. A programmer creates file2.c and opts to define an inline version of this function, and simply copies and pastes the function body. However, the function references mutable static objects, namely objects that maintain the state of the random number generator. Separate invocations of the get_random() function may call different definitions, resulting in a faulty random number generator (because each definition operates on separate static objects).:
| Code Block | ||||
|---|---|---|---|---|
| ||||
/* file1.c */
/* Externally linked definition of the function get_random */
extern unsigned int get_random() {
/* Initialize the seeds */
static unsigned int m_z = 0xdeadbeef;
static unsigned int m_w = 0xbaddecaf;
/* Compute the next random value and update the seeds */
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
|
The second file file2.c defines an inline version of this function that references mutable static objects, namely objects that maintain the state of the random number generator. Separate invocations of the get_random() function might call different definitions, each operating on separate static objects, resulting in a faulty random number generator.
| Code Block | ||||
|---|---|---|---|---|
| ||||
/* file2.c */
/* Inline definition of get_random function */
inline unsigned int get_random() {
/* Initialize the seeds
Constraint violation: static duration storage referenced
in non-static inline definition */
static unsigned int m_z = 0xdeadbeef;
static unsigned int m_w = 0xbaddecaf;
/* Compute the next random value and update the seeds */
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
int main(void) {
unsigned int rand_no;
for (int ii = 0; ii < 100; ii++) {
/*
* Get a random number. Implementation defined whether the
* inline definition in this file or the external definition
* in file2.c is called.
*/
rand_no = get_random();
/* Use rand_no... */
}
/* ... */
/* Get another random number. Behavior Sameis comment from above applies hereimplementation defined. */
rand_no = get_random();
/* Use rand_no... */
return 0;
}
|
...
This compliant solution adds the static modifier to the inline function definition in file2.c, thus internally linking this definition. Now all giving it internal linkage. All references to get_random() in file.2.c will now reference the internally linked definition.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
/* file2.c */
/* Static inline definition of get_random function */
static inline unsigned int get_random() {
/* Initialize the seeds
* No more constraint violation, our inline function is now
* internally linked.
*/
static unsigned int m_z = 0xdeadbeef;
static unsigned int m_w = 0xbaddecaf;
/* Compute the next random value and update the seeds */
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
int main(void) {
/* Generate a bunch of random numbers using get_random()... */
return 0;
}
|
...