I am learning C programming, and my book says that unlike variables, constants cannot be changed during the program's execution. And that their are two types of constants Literal and Symbolic. I think that I understand Symbolic pretty well. But Literal Constants are confusing me.
The example it gave me for was
int count = 20;
I wrote this simple program, and I could change the value of the Literal Constant.
/* Demonstrates variables and constants */
#include <stdio.h>
/* Trying to figure out if literal constants are any different from variables */
int testing = 22;
int main( void )
{
/* Print testing before changing the value */
printf("\nYour int testing has a value of %d", testing);
/* Try to change the value of testing */
testing = 212345;
/* Print testing after changing the value */
printf("\nYour int testing has a value of %d", testing);
return 0;
}
It outputted this:
Your int testing has a value of 22
Your int testing has a value of 212345
RUN SUCCESSFUL (total time: 32ms)
Can someone explain how this happens, am I declaring it wrong? Or is there any difference between normal variable and literal constants?
-Thanks
The literal constant is the 20. You can change the value of count, but you cannot change the value of 20 to be, for example, 19.
(As some trivia, there are versions of FORTRAN where you could do exactly this, so it's not meaningless to talk about)
The literal in this case is the number 22 (and later the number 212345). You assign this literal to a variable testing. This variable can be changed.
This is a little trickier when it comes to strings and string literals. If you have a pointer to a string literal, you can change the actual pointer to point to some other string, but you can change what the original pointer points to.
For example:
const char *string_pointer = "Foobar";
With the above definition, you can not do e.g. string_pointer[0] = 'L';, as that is an attempt to modify the literal string that the pointer points to.
Depending on context, a symbolic constant can be either a "variable" declared as const or a preprocessor macro.
A literal constant in C is just any number itself, e.g. your 20. You cannot change it by doing, say, 20 = 50;. That is illegal.
There are also constant variables, e.g. const int blah = 42;. You cannot change this blah by doing something like blah = 100;.
But if you have a normal, non-constant variable, e.g. int foo = 123;, you can change it, e.g. foo = 456;.
Related
Hey I'm working on a problem and here is what I have to do:-
Write a function called initarray that takes an array of pointers to int and an int representing the size of the array, as arguments. The function should initialize the array with pointers to ints (use malloc) that have a value corresponding to the array indices at which a pointer to them are stored (the pointer stored at array index 2 should point to an integer with a value of 2).
So far I've written this, but It's giving me an error "[Error] variable-sized object may not be initialized"
Can you tell me what I'm doing wrong here?
#include<stdio.h>
void initArray(int **a, int sz){
int i;
for (i = 0; i < sz; i++) {
a[i] = calloc (1, sizeof **a);
*a[i] = i;
}
}
int main(){
const int Var = 10;
int *array[Var] = {NULL};
initArray(array,3);
}
For historical reasons, the value of a const variable is never considered a constant expression in C.
So if you use it as an array dimension, then the array is a variable-length array, and variable-length arrays are not allowed to have initializers.
One solution not mentioned yet is to use enum. Enumerators are in fact constant expressions, and they don't suffer from the same "bigger hammer" issue as preprocessor macros:
int main()
{
enum { Var = 10 };
int *array[Var] = {NULL};
initArray(array,3);
}
C has no symbolic constants with user-defined type. You encountered one of the differences to C++.
The const qualifier just is a guarantee you give to the compiler you will not change the variable(!) Var.
Arrays with initialiser and global arrays require a constant expressing which can be evaluated at compile-time. As Var is semantically still a variable, you cannot use it.
The C-way to emulate symbolic constants are macros:
#define ARRAY_SIZE 10
...
// in your function:
int *array[ARRAY_SIZE] = ...
Macros are handled by the preprocessor and are a textual replacement before the actual compiler sees the code.
Note I changed the name to a more self-explanatory one. The macro should also be at the file-level, typically near the beginning to allow easier modifications. Using the integer constant 10 directly in the code is a bad idea. Such magic numbers are often cause of errors when a modification is required.
The error would suggest that you can't use an initializer (the = {NULL} in your main function) on a variable-sized object. While it looks like it isn't variable (because of the const on Var, and because 10 is a constant) it sees it as variable because you're accessing it through a variable. If you use:
int *array[10] = {NULL}
I think your snippet will work fine.
I was thinking. If this is a variable:
int variable;
variable = 12;
Couldn't you just do this?:
variable = 12;
//Instead of putting int variable before this?
I'm new to C and am learning it, just wanted to understand more of it.
Same thing with chars.
Why is my question being voted down? I'm asking questions and you're all helping....
Couldn't you just do this?:
variable = 12; //Instead of putting int variable before this?
No you can't do this because you must declare it's type first. This
int variable;
defines a variable that can hold an int. If you assign a string, "asdsa2", or a float, 34.5, you will get a compilation error. Because we can assign only variables of type int to the variable.
So char is defining the variable as a string and int is defining it as
an integer.
If you write:
char firstLetter;
defines a variable of type char. That means the variable firstLetter can hold a character.
This is firstLetter='c'; valid. While this firstLetter="21"; is wrong.
I see now, but couldn't you do this instead? int variable
= 12; or char variable = "string";
Of course you do. This is actually the usual way we assign a value to a variable, think it like below
We define the type.
We set the name of the variable.
We place the equal sign, =.
We set the value.
We terminate the assignment with a semicolon, ;.
Follow 1 through 5 from left to right.
C is statically typed, meaning that every variable has a type that needs to be specified. You specify it by putting the type name in the declaration. You can initialise the variable in its declaration, rather than assigning it later:
int variable = 12;
but you can't leave out the declaration altogether. Your second snippet is an assignment to a variable that's already been declared, giving an error if it hasn't been. The compiler needs the declaration to tell it the type so that it knows how to assign to it.
You initially tagged the question with C++; that language allows the type to be deduced from the initialiser, to save you writing it redundantly. But you still need a declaration in that case, to indicate that you mean to introduce a new variable, and haven't just mistyped the name of an existing one:
auto variable = 12; // "auto" is deduced as "int" to match 12
but C doesn't have this.
Well let me tell you. Whenever you want to use a variable in "C", then you will have to define it. Here, "int variable" means that the variable will hold an integer value. Similar is the case for "char" and "float".
This is the rule for defining variables in "C". if you just write "variable=12", then the compiler will not understand which type of value it will hold. Yes, you have to firstly provide the type of the variable so that the compiler understands the variable's data type and compiles accordingly.
In some languages like python, you don't have to declare the data type. When you write something like
int variable;
you are "declaring" it. When you write
variable = 1;
you are "initializing" it. All variables must be declared first in C because it is a low-level language that is concerned with memory and data types.
In C you have to specify a type of your variable.
int variable = 12;
int is the type.
variable is the name of the variable.
12 is the value you initialize it to.
What is a type and why do we need it? A type is essentially a way to tell the system how much memory you want to attach to your variable.
Generally on 32 bit machines you have:
int is 4 bytes, char is 1 byte.
If you did not declare the type, you would be wasteful in giving everything 4 bytes, when it may only need 1.
Also types help the programmer determine what a variable must have, such as a char * being a String of characters usually, an int being an integer, a float being a floating decimal point number. There are many uses in having types, and there are languages that abstract types such as python (well, primitive types.)
both in one line:
int variable = 12;
int is a name of the type and variable is a name of variable of that type
Say I have a two functions like the ones below:
unsigned char PlusTwo(unsigned char value)
{
return (value + 2);
}
unsigned char PlusTwoUsingPtr(unsigned char *value)
{
return (*value + 2);
}
If I want to test the first function while I'm developing, no problem, all I have to do is this:
PlusTwo(8);
The compiler will automatically place a constant somewhere in memory for me. However, to test the second function, it gets more complicated. First I have to declare a variable, then pass the function the address of the variable:
unsigned char eight = 8;
PlusTwoUsingPtr(&eight);
This isn't horribly time consuming, but it is annoying (particularly in C89/ANSI where variables have to be declared at the beginning of a function block). Is there some trick that will allow me to just test this function in one line of code, having the compiler declare & place a constant somewhere for me to point to?
You can use a compound literal with a scalar type:
PlusTwoUsingPtr(&((unsigned char){8}));
Compound literal is a feature introduced in C99.
For information the object is mutable (with static storage duration) and you can also modify it in your function.
Is there any way in C to find if a variable has the const qualifier? Or if it's stored in the .rodata section?
For example, if I have this function:
void foo(char* myString) {...}
different actions should be taken in these two different function calls:
char str[] = "abc";
foo(str);
foo("def");
In the first case I can modify the string, in the second one no.
Not in standard C, i.e. not portably.
myString is just a char* in foo, all other information is lost. Whatever you feed into the function is automatically converted to char*.
And C does not know about ".rodata".
Depending on your platform you could check the address in myString (if you know your address ranges).
You can't differ them using the language alone. In other words, this is not possible without recurring to features specific to the compiler you're using, which is likely not to be portable. A few important remarks though:
In the first case you COULD modify the string, but you MUST NOT. If you want a mutable string, use initialization instead of assignment.
char *str1 = "abc"; // NOT OK, should be const char *
const char *str2 = "abc"; // OK, but not mutable
char str3[] = "abc"; // OK, using initialization, you can change its contents
#include<stdio.h>
void foo(char *mystr)
{
int a;
/*code goes here*/
#ifdef CHECK
int local_var;
printf(" strings address %p\n",mystr);
printf("local variables address %p \n",&local_var);
puts("");
puts("");
#endif
return;
}
int main()
{
char a[]="hello";
char *b="hello";
foo(a);
foo(b);
foo("hello");
}
On compiling with gcc -DCHECK prog_name.c and executing on my linux machine the following output comes...
strings address 0xbfdcacf6
local variables address 0xbfdcacc8
strings address 0x8048583
local variables address 0xbfdcacc8
strings address 0x8048583
local variables address 0xbfdcacc8
for first case when string is defined and initialized in the "proper c way for mutable strings" the difference between the addresses is 0x2E.(5 bytes).
in the second case when string is defined as char *p="hello" the differences in addresses is
0xB7D82745.Thats bigger than the size of my stack.so i am pretty sure the string is not on the stack.Hence the only place where you can find it is .rodata section.
The third one is similar case
PS:As mentioned above this isn't portable but the original question hardly leaves any scope for portability by mentioning .rodata :)
GCC provides the __builtin_constant_p builtin function, which enables you to determine whether an expression is constant or not at compile-time:
Built-in Function: int __builtin_constant_p (exp)
You can use the built-in function __builtin_constant_p to determine if a value is known to be constant at compile-time and hence that GCC can perform constant-folding on expressions involving that value. The argument of the function is the value to test. The function returns the integer 1 if the argument is known to be a compile-time constant and 0 if it is not known to be a compile-time constant. A return of 0 does not indicate that the value is not a constant, but merely that GCC cannot prove it is a constant with the specified value of the `-O' option.
So I guess you should rewrite your foo function as a macro in such a case:
#define foo(x) \
(__builtin_constant_p(x) ? foo_on_const(x) : foo_on_var(x))
foo("abc") would expand to foo_on_const("abc") and foo(str) would expand to foo_on_var(str).
Suppose I have a constant defined in a header file
#define THIS_CONST 'A'
I want to write this constant to a stream. I do something like:
char c = THIS_CONST;
write(fd, &c, sizeof(c))
However, what I would like to do for brevity and clarity is:
write(fd, &THIS_CONST, sizeof(char)); // error
// lvalue required as unary ‘&’ operand
Does anyone know of any macro/other trick for obtaining a pointer to a literal? I would like something which can be used like this:
write(fd, PTR_TO(THIS_CONST), sizeof(char))
Note: I realise I could declare my constants as static const variables, but then I can't use them in switch/case statements. i.e.
static const char THIS_CONST = 'A'
...
switch(c) {
case THIS_CONST: // error - case label does not reduce to an integer constant
...
}
Unless there is a way to use a const variable in a case label?
There is no way to do this directly in C89. You would have to use a set of macros to create such an expression.
In C99, it is allowed to declare struct-or-union literals, and initializers to scalars can be written using a similar syntax. Therefore, there is one way to achieve the desired effect:
#include <stdio.h>
void f(const int *i) {
printf("%i\n", *i);
}
int main(void) {
f(&(int){1});
return 0;
}
These answers are all outdated, and apart from a comment nobody refers to recent language updates.
On a C99-C11-C17 compiler using a compound literal, http://en.cppreference.com/w/c/language/compound_literal, is possible to create
a pointer to a nameless constant, as in:
int *p = &((int){10});
The only way you can obtain a pointer is by putting the literal into a variable (your first code example). You can then use the variable with write() and the literal in switch.
C simply does not allow the address of character literals like 'A'. For what it's worth, the type of character literals in C is int (char in C++ but this question is tagged C). 'A' would have an implementation defined value (such as 65 on ASCII systems). Taking the address of a value doesn't make any sense and is not possible.
Now, of course you may take the address of other kinds of literals such as string literals, for example the following is okay:
write(fd, "potato", sizeof "potato");
This is because the string literal "potato" is an array, and its value is a pointer to the 'p' at the start.
To elaborate/clarify, you may only take the address of objects. ie, the & (address-of) operator requires an object, not a value.
And to answer the other question that I missed, C doesn't allow non-constant case labels, and this includes variables declared const.
Since calling write() to write a single character to a file descriptor is almost certainly a performance killer, you probably want to just do fputc( THIS_CONST, stream ).
#define THIS_CONST 'a'
Is just a macro. The compiler basically just inserts 'a' everywhere you use THIS_CONST.
You could try:
const char THIS_CONST = 'a';
But I suspect that will not work wither (don't have a c-compiler handy to try it out on, and it has been quite a few years since I've written c code).
just use a string constant, which is a pointer to a character, and then only write 1 byte:
#define MY_CONST_STRING "A"
write(fd, MY_CONST_STRING, 1);
Note that the '\0' byte at the end of the string is not written.
You can do this for all sorts of constant values, just use the appropriate hex code string, e.g.
#define MY_CONST_STRING "\x41"
will give also the character 'A'. For multiple-byte stuff, take care that you use the correct endianness.
Let's say you want to have a pointer to a INT_MAX, which is e.g. 0x7FFFFFFF on a 32 bit system. Then you can do the following:
#define PTR_TO_INT_MAX "\xFF\xFF\xFF\x7F"
You can see that this works by passing it as a dereferenced pointer to printf:
printf ("max int value = %d\n", *(int*)PTR_TO_INT_MAX);
which should print 2147483647.
For chars, you may use extra global static variables. Maybe something like:
#define THIS_CONST 'a'
static char tmp;
#define PTR_TO(X) ((tmp = X),&tmp)
write(fd,PTR_TO(THIS_CONST),sizeof(char));
There's no reason the compiler has to put the literal into any memory location, so your question doesn't make sense. For example a statement like
int a;
a = 10;
would probably just be directly translated into "put a value ten into a register". In the assembly language output of the compiler, the value ten itself never even exists as something in memory which could be pointed at, except as part of the actual program text.
You can't take a pointer to it.
If you really want a macro to get a pointer,
#include <stdio.h>
static char getapointer[1];
#define GETAPOINTER(x) &getapointer, getapointer[0] = x
int main ()
{
printf ("%d\n",GETAPOINTER('A'));
}
I can see what you're trying to do here, but you're trying to use two fundamentally different things here. The crux of the matter is that case statements need to use values which are present at compile time, but pointers to data in memory are available only at run time.
When you do this:
#define THIS_CONST 'A'
char c = THIS_CONST;
write(fd, &c, sizeof(c))
you are doing two things. You are making the macro THIS_CONST available to the rest of the code at compile time, and you are creating a new char at runtime which is initialised to this value. At the point at which the line write(fd, &c, sizeof(c)) is executed, the concept of THIS_CONST no longer exists, so you have correctly identified that you can create a pointer to c, but not a pointer to THIS_CONST.
Now, when you do this:
static const char THIS_CONST = 'A';
switch(c) {
case THIS_CONST: // error - case label does not reduce to an integer constant
...
}
you are writing code where the value of the case statement needs to be evaluated at compile time. However, in this case, you have specified THIS_CONST in a way where it is a variable, and therefore its value is available only at runtime despite you "knowing" that it is going to have a particular value. Certainly, other languages allow different things to happen with case statements, but those are the rules with C.
Here's what I'd suggest:
1) Don't call a variable THIS_CONST. There's no technical reason not to, but convention suggests that this is a compile-time macro, and you don't want to confuse your readers.
2) If you want the same values to be available at compile time and runtime, find a suitable way of mapping compile-time macros into run-time variables. This may well be as simple as:
#define CONST_STAR '*'
#define CONST_NEWLINE '\n'
static const char c_star CONST_STAR;
static const char c_newline CONST_NEWLINE;
Then you can do:
switch(c) {
case CONST_STAR:
...
write(fd, &c_star, sizeof(c_star))
...
}
(Note also that sizeof(char) is always one, by definition. You may know that already, but it's not as widely appreciated as perhaps it should be.)
Here is another way to solve this old but still relevant question
#define THIS_CONST 'A'
//I place this in a header file
static inline size_t write1(int fd, char byte)
{
return write(fd, &byte, 1);
}
//sample usage
int main(int argc, char * argv[])
{
char s[] = "Hello World!\r\n";
write(0, s, sizeof(s));
write1(0, THIS_CONST);
return 0;
}
Ok, I've come up with a bit of a hack, for chars only - but I'll put it here to see if it inspires any better solutions from anyone else
static const char *charptr(char c) {
static char val[UCHAR_MAX + 1];
val[(unsigned char)c] = c;
return &val[(unsigned char)c];
}
...
write(fd, charptr(THIS_CONST), sizeof(char));