Is there a way to check if a variable has been initialized or not in C?
Consider the following example,
int main(){
int a = 3, b = 7, c;
if ( a > b )
c = a-b;
// Now, how can I check if the variable "c" has some value or not
// I don't want check like this,
// if ( isalpha(c) ) or if ( isdigit(c) )
// or anything similar to like that
}
In other words, does C has some function like defined in Perl. In Perl, I can simply do if (defined c)that would check if the variable is defined or not, and it'd return False for above example. How can I achieve the same in C?
C does not have this ability. You have two main options:
A sentinel value
For example, if you know that the value of c will never be negative, then initialize it to -1, and test that for that.
Add another variable
Create another variable bool we_set_c_to_something = false; and then set it to true when you write to c.
C is a compiled language which doesn't support runtime variable binding, while Perl is a interpreted language which support dynamic typing. So you can check the definition of a variable in Perl, but not in C.
When you declare a variable in C int c;, this variable c is defined but without initialization. The declaration and definition are in one statement.
The definition of a variable in C is not checked by code writer. The compilers do it for you. When compile and link your C code, the compiler will check all variable's definitions. An error will be invoked and the compiling or linking process will stop if there are undefined variables found in your code.
Hope this will make you distinguish the differences.
Wrong question. You're not asking whether the variable is defined. If the variable is not defined then compilation fails. Look up the difference between "declaration" and "definition". In the case of those local variables, you have defined the variable c.
What you're looking for is initialisation. Many compilers will warn you about using variables before they're initialised, but if you persist in running that code then the assumption is that you know better than the compiler. And at that point it's your problem. :) Some languages (e.g. Perl) have an extra flag that travels along with a variable to say whether it's been initialised or not, and they hide from you that there's this extra flag hanging around which you may or may not need. If you want this in C, you need to code it yourself.
Since C++ allows operator overloading, it's relatively easily to implement this in C++. Boost provides an "optional" template which does it, or you could roll your own if you want a coding exercise. C doesn't have the concept of operator overloading though (hell, the concept didn't really exist, and the compilers of the day probably couldn't have supported it anyway) so you get what you get.
Perl is a special case because it rolls the two together, but C doesn't. It's entirely possible in C to have variables which are defined but not initialised. Indeed there are a lot of cases where we want that to be the case, particularly when you start doing low-level access to memory for drivers and stuff like that.
Related
Is there a difference between the following two approaches to defining a for-loop variable in C?
int i;
for (i = 0; i < X; i++) {
// something
}
And:
for (int i = 0; i < X; i++) {
// something
}
My preference is to use the second approach if the i is just always a throw-away, but is there any reason that it wouldn't be a good idea to do that?
Yes.
As the i variable is usually used only to count the number of iterations needed, it doesn't make sense to have a variable live outside the scope of the loop. That, if you can, should be avoided.
As some comments to the question mention, there are some cases in which you can't use the second, but that's not the general case.
As for the compiler later compiling to the same assembly, that may be true, but conceptually the second is cleaner, and for someone reading the code from outside, it makes it clear that the variable is never used again.
Hope this helps!
but is there any reason that it wouldn't be a good idea to do that?
In C, you should prefer the second form, because it reduces the scope of the variable and makes it more obvious where it is going to be used. Unless...
...it goes against the coding guidelines of a given project. For instance, the Linux kernel declares all variables at the top of a function.
...you want to be conforming to C90: you cannot use loop initial declarations.
In C++, however, objects may have very expensive constructors, which means that, at times, you may want to re-use them rather than initialize a new one every time (e.g. if you construct a new one within the body of the loop).
There are a number of differences between the two.
The second form is illegal in the 1989 ANSI (1990 ISO) C standard. The first is supported in C from 1999 and in standard C++. It is supported by some C compilers older than 1999, either as a non-standard or optional extension or because those compilers were actually C++ compilers with a C mode.
In the first form, i exists after the loop, so its value can still be accessed, but redefining it results in a diagnostic (compile time error). In the second form, i does not exist after the loop, so accessing its value after the loop gives a diagnostic, but i can be redefined.
In general terms, it is advisable to ensure that variables only exist for as long as needed, and cease to exist when no longer needed. The second form explicitly allows that.
Obviously, variables that need to exist outside the loop, need to be defined outside it. But, if the variable i is not needed outside the loop, then I would favour the second form. This allows the compilers to catch problems, such as unintended use of variable i after the loop.
Some older C and C++ compilers (mainly dating from before the 1998 C++ standard was ratified, but some from the early 2000s) implement the second form so the variable i still exists after the loop. This effectively makes the two forms equivalent when using those compilers.
I am not a developer but I understand some C concepts. However, I'm having a hard time finding where the enums (e.g NR_LRU_LISTS, etc) in meminfo.c/meminfo_proc_show() and the variables (e.g. totalram_pages, etc) in page_alloc.c/si_meminfo() are set.
What I meant by set is for example NR_LRU_LISTS = 324077 for instance. What I understood there is that LRU_ACTIVE_FILE equals 3, but there's no = operator in front of NR_LRU_LISTS, so it must be set somewhere else.
I've clicked on the enums/variables to see where they may be called, but there's either too much unrelevant or either non-defining references.
The last thing would be me not being aware of something, but what ?
To be honest, my goal here is to determine how /proc/meminfo 's values are calculated.
But, here my question is: Where do these enums and variables are set ?
Update 1:
The enums part is now solved, and NR_LRU_LISTS equals 5.
But the totalram_pages part seems to be harder to find out...
The constants you are asking about are defined using C's "enum" feature.
enum Foo { A = 4, B, C };
declares constants named A, B, and C with values 4, 5, 6 respectively.
Each constant with no initializer is set to one more than the previous constant. If the first constant in an enum declaration has no initializer it is set to zero.
The variables you are asking about are defined with no initializer, at file scope (that is, outside of any function). For instance, totalram_pages is defined on line 128 of page_alloc.c, with a public declaration for use throughout the kernel on line 50 of linux/mm.h. Because they are defined at file scope and they don't have initializers, they are initialized to zero at program start. (This is a crucial difference from variables defined inside a function with no initializers. Those start off with "indeterminate" values, reading which provokes undefined behavior.)
I do not know how totalram_pages receives a meaningful value. This code is too complicated for me to want to track that down right now.
It sounds like you are just beginning to learn C. Studying other people's code is a good way to learn, but you should start with simple programs. The Linux kernel is not simple, and because it's an operating system kernel, it also does a lot of things that would be considered bad style or just plain wrong in any other program. Don't start with it.
... That said, declaring a bunch of related constants using an enum and letting them take sequential values implicitly is totally normal and good style, and so is defining variables at file scope with no initializer and relying on them to be zero at program start. (It is often wrong to have a global variable in the first place, but if you genuinely need one, relying on implicit initialization to zero is not wrong.) These are things you need to understand and things you are likely to want to do yourself in due course.
I am reading files of xv6 kernel and I cannot understand what the following means:
static int (*syscalls[])(void) = {
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
...
}
Can someone explain this to me? Especially what square brackets (e.g [SYS_fork]) mean.
Thank you
That code is making an array of function pointers, using an old alternative GNU extension for designated initialization.
Designated initializations is a feature that was added to C in C99 that lets you specify which array index to assign a specific value for arrays, so they need not be in order. The same feature exists for struct initializations where you can specify the specific field to assign a given value to.
The C99 syntax for array designated initializations is [index] = value. This code in particular though is using an older alternative syntax from GCC, which as per this document has been obsolete since GCC 2.5, in which there is no equals sign used.
In syscall.c the indices are specified using macros defined in syscall.h, the first of which is defined to 1 in syscall.h, et.c.
This is most likely a non-standard way of initializing an array of function pointers. The identifiers SYS_fork etc. are very likely macros or enum constants specifying the element index.
Another possibility is that this is not a C file, but is turned into a syntactically valid C file using some filtering tool prior to compilation.
I'm discussing with a friend what's the correct way to declare some variables in C, exactly in the for loop.
He has a compiler I can't remember and I have Dev-C++.
He does:
for (int i = 0; i<10; i++)
// ... and it works
I do:
int i;
for (i = 0; i<10; i++)
// ... and it works
If I do it like he does, Dev-C++ gives me an error. What's the technically correct way to do this? I was taught to do it the way I do but now I'm confused because he does it in the other way and it works for him D:
Declaring the variable in the loop, like your friend does, is supported in C99 and in C++. It is likely that your friend is coming from a C++ background, where such style of declaration is the norm. Declaring the loop variable outside the loop, like you do, is correct in older C, such as C89, which is what your compiler apparently supports.
If you have access to a C99 compiler, which style to choose is mostly a matter of preference. Seasoned C programmers don't mind declaring variables outside loop bodies, but it is considered slightly cleaner to declare them inside because it restricts the scope of the variable to the least possible lexical region. Declaring the variable outside the loop body is, of course, necessary if you plan to use it after the loop is done — for example, to inspect how far the loop has progressed.
Depending of which version of C you're using. Ansi C (original, Ritchie & Kernighan) only supports declaration at begin of block while modern C (and any flavour of C++) allows mixing statement and declaration.
{
int a;
printf ("Stuff);
int b; /* not allowed */
}
Declaring a value inside of the for-loop header causes an error in any compiler that predates c99. If you compile this with the c99 standard or newer, it will work just fine.
Formally the physical difference between THESE TWO is the performance. put the definition within the brackets after for may have more chances to be as a register-only variables. But on the other hand there are many other factors which can decide the detail of optimization results, with the help of the analizing mechanism of the compiler. So the final result may be no different or even be opposite.
There is indeed a different for sure: if you define a variable within the brackets after 'for', that variable won't be able to be used at the outside of that for-loop.
I'm quite often confused when coming back to C by the inability to create an array using the following initialisation pattern...
const int SOME_ARRAY_SIZE = 6;
const int myArray[SOME_ARRAY_SIZE];
My understanding of the problem is that the const operator does not guarantee const-ness but rather merely asserts that the value pointed to by SOME_ARRAY_SIZE will not change at runtime. But why can the compiler not assume that the value is constant at compile time? It says 6 right there in the source code...
I think I'm missing something core in my fundamental understanding of C. Somebody help me out here. :)
[UPDATE]After reading a bit more around C99 and variable length arrays I think I understand this a bit better. What I was trying to create was a variable length array - const does not create a compile time constant but rather a runtime constant. Therfore I was initialising a variable length array, which is only valid in C99 at a function/block scope. A variable length array at the file scope is impossible as the compiler cannot assign a fixed memory address to an unbounded array.[/UPDATE]
Well, in C++ the semantics are a bit different. In C++ your code would work fine. You must distinguish between 2 things, const and constant expression. Const means simply, as you described, that the value is read-only. constant expression, on the other hand, means the value is known compile time and is a compile-time constant. The semantics of const in C are always of the first type. The only constant expressions in C are literals, that's why #define is used for such kind of things.
In C++ however, any const object initialized with a constant expression is in itself a constant expression.
I don't know exactly WHY this is so in C, it's just the way it is
The problem is that the language syntax demands a integer value between the [ ]. SOME_ARRAY_SIZE is still a variable (even if you told the compiler nobody is allowed to vary it!)
The const keyword is basically a read-only indication. It does not, really, indicate the underlying value will not change, even though that is the case in your example.
When it comes to pointers, this is more clear:
void foo(int const * p)
{
if (*p == 100)
{
bar();
/* Here, the compiler can not assume that *p is 100 */
}
}
In this case, a compiler should not accept the code in your example, as it requires the array size to be constant. If it would accept it, the user could later run into trouble when porting the code a more strict compiler.
You can do this in C99, and some compilers prior to C99 also had support for this as an extension to C89 (e.g. gcc). If you're stuck with an old compiler that doesn't have C99 support though (e.g. MSVC) then you'll have to do it the old skool way and use a #define for the array size.
Note that that above comments apply only to such declarations at local scope (i.e. automatic variables). C99 still doesn't allow such declarations at global scope.
i just did a very quick test with my Xcode and Objective C file I currently had open on my machine and put this in the .m file:
const int arrs = 6;
const int arr[arrs];
This compiles without any issues.