114

I often see in C and C++ code the following convention:

some_type val;
val = something;

some_type *ptr = NULL;
ptr = &something_else;

instead of

some_type val = something;
some_type *ptr = &something_else;

I initially assumed that this was a habit left over from the days when you had to declare all local variables at the top of the scope. But I've learned not to dismiss so quickly the habits of veteran developers. So, is there a good reason for declaring in one line, and assigning afterwards?

1
  • 15
    +1 for "I've learned not to dismiss so quickly the habits of veteran developers." That's a wise lesson to learn.
    – Wildcard
    Commented Nov 30, 2015 at 15:56

7 Answers 7

104

C

In C89 all declarations had to be be at the beginning of a scope ({ ... }), but this requirement was dropped quickly (first with compiler extensions and later with the standard).

C++

These examples are not the same. some_type val = something; calls the copy constructor while val = something; calls the default constructor and then the operator= function. This difference is often critical.

Habits

Some people prefer to first declare variables and later define them, in the case they are reformatting their code later with the declarations in one spot and the definition in an other.

About the pointers, some people just have the habit to initialize every pointer to NULL or nullptr, no matter what they do with that pointer.

14
  • 1
    Great distinction for C++, thanks. What about in plain C? Commented May 7, 2011 at 20:35
  • 14
    The fact that MSVC still doesn't support declarations except at the beginning of a block when it's compiling in C mode is the source of endless irritation for me. Commented May 7, 2011 at 22:03
  • 5
    @Michael Burr: This is because MSVC doesn't support C99 at all.
    – orlp
    Commented May 7, 2011 at 22:05
  • 4
    "some_type val = something; calls the copy constructor": it may call the copy constructor, but the Standard allows the compiler to elide the default-construction of a tempory, copy construction of val and destruction of the temporary and directly construct val using a some_type constructor taking something as sole argument. This is a very interesting and unusual edge case in C++... it means there's a presumption about the semantic meaning of these operations.
    – Tony
    Commented May 9, 2011 at 9:15
  • 2
    @Aerovistae: for built-in types they are the same, but the same can not always be said for user-defined types.
    – orlp
    Commented Oct 11, 2012 at 18:48
30

You have tagged your question C and C++ at the same time, while the answer is significantly different in these languages.

Firstly, the wording of the title of your question is incorrect (or, more precisely, irrelevant to the question itself). In both of your examples the variable is declared and defined simultaneously, in one line. The difference between your examples is that in the first one the variables are either left uninitialized or initialized with a dummy value and then it is assigned a meaningful value later. In the second example the variables are initialized right away.

Secondly, in C++ language, as @nightcracker noted in his answer these two constructs are semantically different. The first one relies on initialization while the second one - on assignment. In C++ these operations are overloadable and therefore can potentially lead to different results (although one can note that producing non-equivalent overloads of initialization and assignment is not a good idea).

In the original standard C language (C89/90) it is illegal to declare variables in the middle of the block, which is why you might see variables declared uninitialized (or initialized with dummy values) at the beginning of the block and then assigned meaningful values later, when those meaningful values become available.

In C99 language it is OK to declare variables in the middle of the block (just like in C++), which means that the first approach is only needed in some specific situations when the initializer is not known at the point of declaration. (This applies to C++ as well).

14
  • 2
    @Jonathan Sterling: I read your examples. You probably need to brush up on the standard terminology of C and C++ languages. Specifically, on the terms declaration and definition, which have specific meanings in these languages. I'll repeat it again: in both of your examples the variables are declared and defined in one line. In C/C++ the line some_type val; immediately declares and defines the variable val. This is what I meant in my answer.
    – AndreyT
    Commented May 7, 2011 at 20:53
  • 1
    I see what you mean there. You're definitely right about declare and define being rather meaningless the way I used them. I hope you accept my apologies for the poor wording, and poorly-thought-out comment. Commented May 7, 2011 at 20:55
  • 1
    So, if the consensus is that “declare” is the wrong word, I'd suggest that someone with a better knowledge of the standard than me edit the Wikibooks page. Commented May 7, 2011 at 21:11
  • 2
    In any other context declare would be the right word, but since declare is a well-defined concept, with consequences, in C and C++ you can not use it as loosely as you could in other contexts.
    – orlp
    Commented May 7, 2011 at 21:15
  • 2
    @ybungalobill: You are wrong. Declaration and definition in C/C++ is not mutually exclusive concepts. Actually, definition is just a specific form of declaration. Every definition is a declaration at the same time (with few exceptions). There are defining declarations (i.e. definitions) and non-defining declarations. Moreover, normally the therm declaration is used all the time (even if it is a definition), except for the contexts when the distinction between the two is critical.
    – AndreyT
    Commented May 7, 2011 at 21:52
15

I think it's an old habit, leftover from "local declaration" times. And therefore as answer to your question: No I don't think there's a good reason. I never do it myself.

4

I said something about that in my answer to a question by Helium3.

Basically, I say it's a visual aid to easily see what is changed.

if (a == 0) {
    struct whatever *myobject = 0;
    /* did `myobject` (the pointer) get assigned?
    ** or was it `*myobject` (the struct)? */
}

and

if (a == 0) {
    struct whatever *myobject;
    myobject = 0;
    /* `myobject` (the pointer) got assigned */
}
4

The other answers are pretty good. There's some history around this in C. In C++ there's the difference between a constructor and an assignment operator.

I'm surprised no one mentions the additional point: keeping declarations separate from use of a variable can sometimes be a lot more readable.

Visually speaking, when reading code, the more mundane artifacts, such as the types and names of variables, are not what jump out at you. It's the statements that you're usually most interested in, spend most time staring at, and so there's a tendency to glance over the rest.

If I have some types, names, and assignment all going on in the same tight space, it's a bit of information overload. Further, it means that something important is going on in the space that I usually glance over.

It may seem a bit counter-intuitive to say, but this is one instance where making your source take up more vertical space can make it better. I see this as akin to why you shouldn't write jam-packed lines which do crazy amounts of pointer arithmetic and assignment in a tight vertical space -- just because the language lets you get away with such things doesn't mean you should do it all the time. :-)

2

In C, this was the standard practice because variables had to be declared at the start of the function, unlike in C++, where it could be declared anywhere in the function body to be used thereafter. Pointers were set to 0 or NULL, because it just made sure that the pointer pointed to no garbage. Otherwise, there's no significant advantage that I can think of, which compels anyone to do like that.

2

Pros for localising variable definitions and their meaningful initialisation:

  • if variables are habitually assigned a meaningful value when they first appear in the code (another perspective on the same thing: you delay their appearance until a meaningful value is avaialable) then there's no chance of them accidentally being used with a meaningless or uninitialised value (which can easily happen is some initialisation is accidentally bypassed due to conditional statements, short-circuit evaluation, exceptions etc.)

  • can be more efficient

    • avoids overheads of setting initial value (default construction or initialisation to some sentinel value like NULL)
    • operator= can sometimes be less efficient and require a temporary object
    • sometimes (esp. for inline functions) the optimiser can remove some/all inefficiencies

  • minimising the scope of variables in turn minimises average number of variables concurrently in scope: this

    • makes it easier to mentally track the variables in scope, the execution flows and statements that might affect those variables, and the import of their value
    • at least for some complex and opaque objects, this reduces resource usage (heap, threads, shared memory, descriptors) of the program
  • sometimes more concise as you're not repeating the variable name in a definition then in an initial meaningful assignment

  • necessary for certain types such as references and when you want the object to be const

Arguments for grouping variable definitions:

  • sometimes it's convenient and/or concise to factor out the type of a number of variables:

    the_same_type v1, v2, v3;

    (if the reason is just that the type name is overly long or complex, a typedef can sometimes be better)

  • sometimes it's desirable to group variables independently of their usage to emphasise the set of variables (and types) involved in some operation:

    type v1;
    type v2; type v3;

    This emphasises the commonality of type and makes it a little easier to change them, while still sticking to a variable per line which facilitates copy-paste, // commenting etc..

As is often the case in programming, while there can be a clear empirical benefit to one practice in most situations, the other practice really can be overwhelmingly better in a few cases.

1
  • I wish more languages would distinguish the case where code declares and sets the value of a variable which would never be written elsewhere, though new variables could use the same name [i.e. where behavior would be the same whether the later statements used the same variable or a different one], from those where code creates a variable that must be writable in multiple places. While both use cases will execute the same way, knowing when variables may change is very helpful when trying to track down bugs.
    – supercat
    Commented Apr 28, 2014 at 22:50

Not the answer you're looking for? Browse other questions tagged or ask your own question.