Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ISO C90 forbids mixing declarations and code... but allows it in certain instances?

I am using the following flags (where cc is either gcc 4.2 or clang 8.0):

$ cc -Wall -Werror -pedantic -ansi -std=c89 main.c

(I know the -ansi flag is a bit redundant in this case)

The following gives me the expected error

main.c:31:8: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
  vec3 abc = {0};
int main()
{
  vec3 a = {0};
  vec3 b = {0};

  Vec3(2, 2, 2);

  vec3 abc = {0}; // Declared after a function call

  return 0;
}

However, the following does not

int main()
{
  vec3 a = Vec3(0, 1, 2);
  vec3 b = Vec3(0, 1, 2);

  vec3 abc = {0}; // Declared after a function call

  return 0;
}

Surely initializing a variable with a function still counts as mixing declarations and code?

The Vec3 function is very basic; no inline flag set, etc.

vec3 Vec3(float x, float y, float z)
{
  vec3 rtn = {0};

  rtn.x = x;
  rtn.y = y;
  rtn.z = z;

  return rtn;
}
like image 401
Karsten Pedersen Avatar asked Nov 26 '19 11:11

Karsten Pedersen


3 Answers

In this code snippet

  vec3 a = Vec3(0, 1, 2);
  vec3 b = Vec3(0, 1, 2);

  vec3 abc = {0}; // Declared after a function call

there are only declarations. There are no statements. Function calls used to initialize the variables are expressions. They are not statements.

It seems this warning

warning: ISO C90 forbids mixing declarations and code

is confusing. It would be more correctly to write that

warning: ISO C90 forbids mixing declarations and statements

For example even a redundant semicolon introduces a null statement. So in general the compiler should issue a warning even for the following code snippet

  vec3 a = Vec3(0, 1, 2);;
                       ^^^^
  vec3 b = Vec3(0, 1, 2);
like image 87
Vlad from Moscow Avatar answered Nov 09 '22 12:11

Vlad from Moscow


The second function has three consecutive variable definitions with initializers — that isn't a problem.

What C90 (C89) does not allow is a declaration after a statement — within a given statement block (between { and }), the declarations must all precede any statements (non-declarations). A plain function call, not part of an initializer, is a statement.

That's why the GCC option for reporting on the problem is -Wdeclaration-after-statement.

like image 36
Jonathan Leffler Avatar answered Nov 09 '22 11:11

Jonathan Leffler


You're misunderstanding the constraint. We can have declarations with initializers; the first non-declaration statement marks the end of the declarations, and after that point we're not allowed more declarations in that scope.

Non-declaration statements can be expression-statements (as above), compound statements (such as if or while) or blocks.

like image 33
Toby Speight Avatar answered Nov 09 '22 12:11

Toby Speight