0

Hi i have a test code for calling malloc as below:

#include <stdio.h>
#include <stdlib.h>
int *p;// = (int*)malloc(sizeof(int));
int main() {
//...
}

Of course this code will be fail when compile with the error: initializer element is not constant and i have referenced this question: Malloc function (dynamic memory allocation) resulting in an error when it is used globally. They said that we have to use malloc() in side a function. But if i change my code to:

#include <stdio.h>
#include <stdlib.h>
int *p;
static int inline test_inline(int *x) {
    printf("in inline function \n");
    x = (int*)malloc(sizeof(int));
    return x;
}
test_inline(p);
int main(){
//...
}

As the definition of inline function: "Inline Function are those function whose definitions are small and be substituted at the place where its function call is happened. Function substitution is totally compiler choice." So this mean we can substitute the inline function test_inline in above example with the code inside it and it means we have call malloc() in global ? Question 1: is this wrong about inline or malloc() ?

Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:

#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
    printf("hello");
}
test();
int main() {
//...
}

So this mean in the global we still can declaration and initialization and call function. But when we compile the above code it has a warning that warning: data definition has no type or storage class So why we have this warning with variable b ? I do not see any thing which inconsequential here. And with the line test(); i have call a function outside main(), i know this make no sense because we never run test() but i have no problem, stil build success. So back to question 1 about the malloc(), i think with the answer that "we can not call a function in global or can not initialize", i think it is not true. Is there any explain more reasonable?

  • `malloc` is a runtime operation. Global data is initialized at compile time, thus - it makes no sense to `malloc` at compile time. The reason being is the compiler makes address space optimizations when creating an executable. Global data tends to live in `.rodata`, `.bss`, or `.data` sections of the binary, while dynamically allocated memory comes from the heap. Furthermore, when requesting dynamic memory it is actually the kernel which returns reserved heap-space as the result of a system call - so once again it does not make sense to do this at compile time. – h0r53 Jun 26 '20 at 14:43
  • 2
    The second snippet compiles by pure coincidence. C compiler threats `test();` and `b=1;` as declarations/definitions equivalent to `int test();` and `int b=1;` as legacy C. Since these are compatible with other declaration in the code, it does not cause error. Change the type of `test` to `void` and you will see it. – Eugene Sh. Jun 26 '20 at 14:50
  • @EugeneSh. Just finished putting that into an answer! – Sourav Ghosh Jun 26 '20 at 14:56

4 Answers4

3

Please refer to the comments.

#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;  //this is only allowed, because the previous line is a tentative definition. [1]
int test() {
    printf("hello");
}
test();    // this is taken as a function declaration, not a function call [2]
int main() {
//...
}
  • Case [1]:

Change you code to

    int b = 5; // not a tentative defintion.
    b = 1; // this assignment is not valid in file scope.

you'll see an error.

  • Case [2]:

If the signature of the function differs, you'll again see an error. Example: try the below:

    float test( int x ) {
        printf("hello");
        return 0.5;
    }  //return changed to float, accepts an int as paramater.

    test();  //defaults to int and no parameter - conflict!!

this will produce the error for conflicting types.

So, bottom line, no assignment, function call - all in all, no code that needs to execute at runtime, can be put into file scope. The reason behind that being, unless it's contained in a function that's called from main(), there's no way to know when / how to execute it.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I have edit my code and compile again as your comment and the it make error as you said. So for the question about "call function in global and initialization variable in global", the answer will be "can not call a function in global, only call function in a scope" and "we only can declaration and initialization a variable but can not assign or operate the operator on it ". Am i understanding true ? – Tiến Thành Nguyễn Jun 26 '20 at 15:42
1

You're not calling functions "globally".

Taking your example:

#include <stdio.h>
#include <stdlib.h>
int b;
b = 1;
int test() {
    printf("hello");
}
test();
int main() {
//...
}

In C types default to int. So the lines

int b;
b = 1;

are basically

int b;
int b = 1;

and the lines

int test() {
    printf("hello");
}
test();

are just

int test() {
    printf("hello");
}
int test(); // -> this is just a matching declaration

Have a look at: https://godbolt.org/z/3UMQAr

(try changing int test() { ... to char test() { ... and you get a compiler error telling you that those types don't match)

That said, you can't call functions there. Functions are called at runtime by your program (especially malloc, which is asking your OS to allocate memory for you). I'm not a C expert here but as far as I know C doesn't have constexpr functions, which would be the only "exception".

See: Compile-Time Function Execution

Stefan Riedel
  • 796
  • 4
  • 15
0

Question 1: is this wrong about inline or malloc()
kind of: malloc does have to be called in a function, but the variable it works on can be declared global. i.e. int *pointer = NULL;//global scope then pointer = malloc(someByteCount);//called within function. Now, pointer is still global, but also has a memory address pointing to someByteCount bytes of memory.

Question 2: In C, all functions are defined on the same level of a .c file, just like main(void){...return 0}, but all functions (except main(void)) must be called within the {...} of other functions, so in short, functions cannot be called from global space.

Illustration for Q2:

//prototypes
void func1(void);
void func2(void);
void func3(void);

int main(){
    int val = test_inline(p);//...
}

int main(void)
{
    //legal
    func1();
    func2();
    func3();
    
    return 0;
}
//not legal
func1();
func2();
func3();

//definitions
void func1(void)
{
    return 0;
}
void func2(void)
{
    return 0;
}
void func3(void)
{
    return 0;
} 

Errors in syntax of your example (see comments):

int *p = NULL;//initialize before use
static int inline test_inline(int *x) {
    printf("in inline function \n");
    x = (int*)malloc(sizeof(int));
    printf("%p\n", x);
    return 0;
    //return x;//function returns int, not int *
}
//...  test_inline(p);//must be called in a function
int main(void){
    int val = test_inline(p);//function declaration returns int, not pointer
    return 0;

}

This code compiles, and runs, but as noted in comments, usefulness may be lacking.

ryyker
  • 22,849
  • 3
  • 43
  • 87
0

Question 1: is this wrong about inline or malloc() ?

Neither. Your understanding of inline is incorrect. The function call may be replaced with an inline expansion of the function definition. First, let's fix the function definition because the return type int doesn't match the type of what you're actually returning:

static inline int *test_inline( int *x )
{
  printf( "in inline function\n" );
  x = malloc( sizeof *x );
  return x; // x has type int *, so the return type of the function needs to be int *
}

If you call this function like so:

int main( void )
{
  int *foo = test_inline( foo );
  ...
}

what the compiler may do is substitute the function call with the assembly language equivalent of the following:

int main( void )
{
  int *foo;
  do
  {
    printf( "in inline function\n" );
    int *x = malloc( sizeof *x );
    foo = x;
  } while( 0 );
  ...
}

Nothing's happening "globally" here. The substitution is at the point of execution (within the body of the main function), not at the point of definition.

Question 2: In the link i give about malloc function dynamic there is an answer said that "Not only malloc, u can't call any function as you have called here. you can only declare function as global or local there" but i see that we still can call function in global and in global we can initialization not only declaration as below:

In the code

int test() {
    printf("hello");
}
test();

the line test(); is not a function call - it's a (redundant and unnecessary) declaration. It does not execute the function.

Here are some excerpts from the language definition to clarify some of this:

6.2.4 Storage durations of objects
...
3     An object whose identifier is declared without the storage-class specifier _Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.

Bold added. Any variable declared outside the body of a function (such as p in your first code snippet) has static storage duration. Since such objects are initialized before runtime, they cannot be initialized with a runtime value (such as the result of a function call).

6.7.4 Function specifiers
...
6     A function declared with an inline function specifier is an inline function. Making a function an inline function suggests that calls to the function be as fast as possible.138)

The extent to which such suggestions are effective is implementation-defined.139)
138) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline substitution’’. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.

139) For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration

All this means is that the inlined code behaves like it was still a single function definition, even if it's expanded in multiple places throughout the program.

John Bode
  • 119,563
  • 19
  • 122
  • 198