21

I just found this line of code within a function, which puzzles me. Can this make sense in any context or it is undefined behavior?

char * acFilename = acFilename;

EDIT: The compiler complains with Warning C4700, that I am using an uninitialized variable.

Fabian
  • 4,001
  • 4
  • 28
  • 59
  • @IvayloStrandjev: sometimes the compiler can not tell which branches of the code may be executed, and so even though the code is correct you may get a warning about possible use of an uninitialised variable. Typically you would fix this by initialising the variable to something sensible, e.g. 0 or `NULL`. – Paul R Feb 21 '17 at 11:04
  • @PaulR yes that is my point. In fact I think in this case you will still be getting the same warning but for this line. – Ivaylo Strandjev Feb 21 '17 at 11:05
  • 2
    @tuple_cat Tested it, gcc is not complaining with `-Wall` – Ctx Feb 21 '17 at 11:07
  • 2
    http://stackoverflow.com/q/9820027/560648 (and, for bonus points: http://stackoverflow.com/q/8595061/560648) – Lightness Races in Orbit Feb 21 '17 at 11:09
  • @IvayloStrandjev: actually you don't get a warning for this construct from gcc (using `gcc -Wall` and compiling as either C or C++). – Paul R Feb 21 '17 at 11:09
  • 3
    @PaulR Try `-Winit-self`. – melpomene Feb 21 '17 at 11:12
  • 7
    As far as I could research up to now, the current answers all miss the point: the idiom `var x = x` is used to _intentionally_ use a variable uninitialized and suppress the warning for gcc. This is independent from the (probably correct) observation, that it invokes UB according to the standard. Now we only need someone explaining for which situations this could be useful ;) – Ctx Feb 21 '17 at 11:22
  • I've used something similar in the past to suppress a warning about an unused variable that held an RCS $Id$. `char *rcsid = "$Id$"; void* suppress_unused[] = { rcsid, suppress_unused };` – armb Feb 21 '17 at 16:56
  • (That was from memory, so may be wrong in details, but cf. http://web.mit.edu/gnu/doc/html/cvs_17.html#SEC75) – armb Feb 21 '17 at 16:59
  • Near duplicate of: [Is there any use with self assignment of object](http://stackoverflow.com/q/17817064/315052) – jxh Feb 21 '17 at 22:05
  • Also see [Does initialization entail lvalue-to-rvalue conversion? Is `int x = x;` UB?](http://stackoverflow.com/q/14935722/1708801) and [Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?](http://stackoverflow.com/q/23415661/1708801) – Shafik Yaghmour Feb 22 '17 at 03:30
  • 1
    @IvayloStrandjev [clang considers idomatic way to silence warning on otherwise unused variables](https://bugs.llvm.org//show_bug.cgi?id=18878#c2) – Shafik Yaghmour Feb 22 '17 at 06:18

4 Answers4

60

At block scope, in C++, this is undefined behaviour, as the right-hand side reads the variable the variable before it has been initialized (C++14 [dcl.init]/12).

At block scope, in C11, this could either be undefined behaviour or behave as an uninitialized variable, depending on various details of the implementation and the rest of the function, see here for detailed analysis.

At namespace scope, in C++, it is OK well-defined and makes a null pointer. This is because all static variables are zero-initialized before their initializers are considered. (C++14 [basic.start.init]/2).

At file scope in C, it is a constraint violation; static variables must have a constant expression as initializer, and the value of a variable cannot be a constant expression.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • At namespace scope, it is well-defined, but not really "OK" because it's so confusing. Reasonable alternatives which still accomplish the same thing would be writing `= nullptr` or leaving the initializer off entirely. – Ben Voigt Feb 21 '17 at 23:06
  • 1
    It is undefined behaviour if you start using that variable, what is undefined is the value of the variable. I edited it. – CoffeDeveloper Feb 22 '17 at 11:54
  • 1
    @M.M: No but if you replace it with "unspecified value" he's right. Plus "this is undefined behaviour" is grammatically incorrect; you mean "this program _has_ undefined behaviour". And nobody's "vandalised" anything; that's a very strong and inappropriate scare word. – Lightness Races in Orbit Feb 22 '17 at 12:04
  • 1
    sorry I meant "unspecified value" :) sorry If you thinked I was vandalizing, actually I'm pretty sure of how certain languages (C, C++, C#) works even at compiler level. @LightnessRacesinOrbit is right. I just used wrong word but your answer needs to be corrected. Assigning a POD value with a un-initialized POD type causes a unspecified value, that is UB if and only if someone use it. – CoffeDeveloper Feb 22 '17 at 12:08
  • 1
    @M.M: _Nobody cares about the difference between "this is UB" and "this program has UB"_ / You mean, except for the person who literally **just** indicated that he does? – Lightness Races in Orbit Feb 22 '17 at 12:09
  • @M.M I think it is clear it was not wrong. And edits can be improved by the way ^^. I apologized already for the small inaccuracy. – CoffeDeveloper Feb 22 '17 at 12:14
  • Have cleaned up comments (and gone into more detail in my answer) – M.M Feb 24 '17 at 11:11
24

No this code does not make any sense. It's probably a typo, maybe somebody meant to use

char* acFilename = ::acFilename;

or

char* acFilename = m_acFilename;

or something else.

As it stands, it's confusing and unhelpful at best, probably a bug because somebody meant to use a different variable.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • 1
    What does the first line do? – Theodoros Chatzigiannakis Feb 21 '17 at 19:50
  • 6
    @TheodorosChatzigiannakis assigns a global variable to the newly-declared local one. – Ruslan Feb 21 '17 at 20:19
  • 1
    I doubt it's a typo, it's a common idiom to prevent warnings about uninitialized variables. I'm amazed that almost nobody commenting or answering here has seen this before. It might be a bad idea, but it's widely used. – Jonathan Wakely Feb 22 '17 at 12:28
  • @JonathanWakely Maybe I was fortunate enough to work with people who only do this by mistake. It's a bad idea, see M.Ms answer for details why. I would definitely have a discussion with people using this on purpose, they need to learn how to *solve* warnings, not work around them. – nvoigt Feb 22 '17 at 12:50
19

I've seen this before. Since gcc is quite trigger happy with its uninitialized variable warnings this is a trick to silence those warnings. Not sure if it's intentional design choice by gcc or the compiler just being stupid, but I've seen people do this on purpose to make gcc shut up (and in the process break the warning that might be correct in the future).

I would just replace it with an initialization to NULL. This is a bad habit, doesn't work on other compilers and a NULL can't be less correct than an indeterminate value and undefined behavior.

Just to demonstrate how this works (and also because I wanted to know if newer gcc versions still do this):

$ cat foo.c
int
foobar(void)
{
    int foo;
    return foo + foo;
}
$ cc -c -Wall -O2 foo.c
foo.c: In function ‘foobar’:
foo.c:6:13: warning: ‘foo’ is used uninitialized in this function [-Wuninitialized]
  return foo + foo;
         ~~~~^~~~~
$ ed foo.c
[...]
$ cc -c -Wall -O2 foo.c
$ cat foo.c
int
foobar(void)
{
    int foo = foo;
    return foo + foo;
}
$ cc -c -Wall -O2 foo.c
$ cc -v
[...]
gcc version 6.2.0 20161005 (Ubuntu 6.2.0-5ubuntu12)
$
Art
  • 19,807
  • 1
  • 34
  • 60
  • 2
    Why would you want to silence the warning in this particular example? It tells you about a serious bug. – M.M Feb 21 '17 at 12:31
  • 6
    @M.M I wouldn't want it. The example is there to show how gcc behaves. – Art Feb 21 '17 at 12:32
  • @M.M: Some functions only pay attention to their arguments in certain situations and ignore them in others. If some code paths set the value of a variable, while others do not set it and use the variable for no purpose but to pass it to a function which (based on other arguments) will end up ignoring it, machine code to initialize the variable would serve no purpose. – supercat Feb 21 '17 at 18:29
  • @Art May I ask why you are using `ed`? – tomsmeding Feb 21 '17 at 21:24
  • 2
    @tomsmeding Why not? – Ry- Feb 21 '17 at 21:48
  • @tomsmeding Because I knew I would include it in the cut 'n paste and thought it would be funny. – Art Feb 22 '17 at 06:34
2

At some locations within a program, it may be possible for a variable to be in either of the following conditions:

  1. Inputs that have been received have caused the variable to be written, and will also cause code to use its value in future.

  2. Inputs that have been received have caused the variable not to be written, but will also cause code not to make any use of its value.

Some compilers will squawk if they see that there exist inputs which would cause a variable to not to get written, and there exist inputs which would cause the variable to be read. Even if the only input which would cause the variable to get read would also cause it to get written, the compilers may not realize that. While it would be possible to silence the compiler's complaints by unconditionally initializing the variable, machine code which initializes the variable with a value which can never actually get used would serve no functional purpose. A source code construct which would silence the compiler's complaints but not result in the compiler generating useless machine code may thus be preferable to one which would need to generate useless machine code. On some compilers, a self-initializing declaration may serve such a purpose.

If a type has trap representations, there may be no practical alternative to writing an initialization that a compiler will likely turn into useless machine code, but if a type doesn't have trap representations there is no particular reason why a quality compiler should force programmers to ask for useless code they don't want and don't need. Rather than try to have different rules for platforms where various types do and don't have trap representations, however, the authors of the Standard defer to implementers' judgments as to what sorts of behavior would be sensible on for a particular target platform and application field.

If on some platform a compiler couldn't allow programmers to omit initialization for variables which are copied but otherwise unused without having to generate likely-redundant initializations itself, it would make sense to require the programmer to include initializations in all situations that could actually occur. On another platform where copying a meaningless value would simply cause the destination to hold a meaningless value, however, it would generally make more sense to allow a programmer to omit initialization in cases where none of the copies would ever end up getting used for any real purpose. The authors of the Standard make no effort to specify what would make sense in any particular case, because they expect that people writing implementations should be capable of exercising good judgment.

The best approach for dealing with this situation would probably be to write a macro which accepts a variable, and whose expansion will initialize the variable to zero (for implementations whose authors judge that there is more value in allowing the compilers to jump the rails when an uninitialized variable is copied, even if none of the copies are really "used" for anything, than there would be in guaranteeing that the mere act of copying a variable will have no side-effects) or else do nothing (when using an implementation which will stay on the rails even without the useless initialization).

supercat
  • 77,689
  • 9
  • 166
  • 211