Today while I was developing a C program a college of mine pointed out that I was doing something wrong.
He said that the code that I was doing which is similar to the code below is wrong, and that you can't define a constant based on another constant.
The program ended up working anyway, and I was left wondering if he was right.
Is the code below wrong/breaks best practices?
const int num=5;
const int num2=num*2;
These are not constants; they are int variables with a const qualifier. The const qualifier means that the variable cannot be written to by the program. Examples of actual integer constant expressions include 5, 2 + 3, and sizeof(int). Here is a full list.
At file scope the second line is a constraint violation, because the name of a variable is not a constant expression. The constraint is C11 6.7.9/4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
(variables declared at file scope have static or thread storage duration).
At block scope the code is OK, because initializers do not need to be constant expressions there.
The classic way to achieve this in C (as you probably know) is to write
#define NUM 5
#define NUM2 (NUM*2)
There are parentheses around the expression, but no semicolons at the end of the lines, because the preprocessor expands the macros as simple lexical substitution. So, the expression 20/NUM2 would expand to 20/(5*2). Without parentheses, it would have been 20/5*2, which is wrong.
Incidentally, in C++, you can use constexpr to get the behavior you want; a constexpr variable can be used in a static initializer or template parameter.
Related
I'm trying to pass values of two variables to be the dimension of the students_grades_db array, but it doesn't work and I don't know why, as both are constant variables.
const int number_students = 4;
const int number_of_notes = 4;
float students_grades_db[number_students][number_of_notes] = {0};
It doesn't work :(
A global array declaration must have constant expressions for index sizes. References to variables (even const variables) are not constant expressions, so can't be used.
You can instead use preprocessor macros that expand to constant literals:
#define number_of_students 4
#define number_of_notes 4
If you declare an array outside a function at file scope, it will then get static storage duration. All variables with static storage duration must have compile-time constants as initializers and if they are arrays, the array sizes must also be compile-time constants.
This means that the size has to be something like an integer constant 123 or an expression containing only integer constants.
The const keyword, non-intuitively, does not make something a compile-time constant, it only makes something read-only. C and C++ are different here, you code would work in C++.
Possible solutions:
Move students_grades_db inside a function. Then you can declare array sizes using any kind of expression, including common int variables. You probably shouldn't declare that array as "global" anyhow.
Or swap out your constants for #define number_students 4.
As per 6.6.10
10 An implementation may accept other forms of constant expressions.
the implementation may consider const (or even not const as answers are focused on it - but it is not the core of the question) variables as constant expressions.
Is my logic correct? If not why?
Some examples:
//file scope
int a = 5;
const int b = 10;
int c[a];
int d[b];
IMO both meet the requirements. They can be evaluated compile time. The value is known and the static arrays have sizes known compile time.
volatile int x = 5; //cannot be considered as known compile time. ????
void foo(int a)
{
static int b[a];
}
In this example a cannot be evaluated compile time - so it cannot be used as constant expression
Constant expressions doesn't have anything to do with the const qualifier. See 6.6/6 for the definition of an integer constant expression.
6.6/10 refers to the earlier parts of the same chapter speaking of integer constant expressions, constant expressions in initializers and so on. I believe the quoted part refers to various corner case expressions such as this:
static int x;
static int y = (int)&x;
This isn't strictly conforming since &x is not regarded as a integer constant expression but as an address constant. Neither gcc nor clang accepts it. I believe 6.6/10 allows compilers to support code like the above example as an implementation-defined extension.
Building on the link from #ryyker 's comment.
In C, an expression is considered constant if it's made entirely out of compile-time constants (i.e. literals). const variables are not accepted because const doesn't necessarily mean "constant"; it just means that a variable is immutable (read-only) from the perspective of the current compilation unit.
Consider a function like this one...
int add(const int a, const int b) {
return a + b;
You could call this function by passing in compile-time constants, but you could also pass in mutable variables. If you pass in a variable, it is treated as const (read-only) for the purposes of that scope, but its value still isn't known at compile time so it isn't a "constant".
I wish to declare a statically allocated array.
Let's take a look at the following code:
#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST 16
#define SLOW 6
#define MAX_NUM MAX(FAST,SLOW)
U8* pBuffers[MAX_NUM];
When MAX_NUM being evaluated by the GCC compiler(FAST and SLOW are constants)?
I would like to make sure that MAX_NUM is constant and being evaluated as part of a compilation or by the pre-processor.
When you launch the compiler, the following phases are (sequentially) performed:
preprocessing: it manages #define, #ifdef / #endif...
code generation: it produces the machine code runnable on target CPU
optimization: it optimizes depending on user options
During the preprocessing phase, the preprocessor will for example "replace" your line with:
U8* pBuffers[MAX(FAST,SLOW)]
then:
U8* pBuffers[((FAST)>(SLOW)?(FAST):(SLOW))]
then finally:
U8* pBuffers[((16)>(6)?(16):(6))]
Indeed, the preprocessor is not very clever and does not go further.
During the code generation phase, your line will be interpreted as:
U8* pBuffers[16]
Because the code generator is very clever.
The C standard requires the sizes of most arrays to be declared using an integer constant expression, which can be, and in this case is required to be, fully evaluated at compile time. (The only exception is "variable length arrays", and those have to be function-local variables with "automatic storage duration" — not statically allocated.)
Therefore, one answer to your question is you don't have to worry about it. If you write
WHATEVER_TYPE variable[SOME EXPRESSION];
at file scope, either SOME EXPRESSION will be evaluated to a constant at compile time, or compilation will fail and you will get an error.
But a more useful answer is to explain how to see for yourself whether SOME EXPRESSION is an integer constant expression, when you are reading code. First, you have to mentally expand all of the macros. Then, you will presumably have an arithmetic expression of some sort (if not, it's a syntax error).
This arithmetic expression is a constant expression if it has no side-effects, doesn't make any function calls, and doesn't refer to the value of any variable (not even if it is const) (enum constants are fine, though, as are string literals, and sizeof variable as long as variable is completely declared and isn't a variable-length array). It is an integer constant expression if, in addition, it doesn't try to do any floating-point or pointer arithmetic (you are allowed to write a floating-point literal as the immediate operand of a cast, though; for instance ((int)3.1415926) is an integer constant expression).
So, to take your example,
#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST 16
#define SLOW 6
#define MAX_NUM MAX(FAST,SLOW)
U8* pBuffers[MAX_NUM];
after macro expansion we have
U8* pBuffers[((16)>(6)?(16):(6))];
The expression inside the square brackets has no side effects, doesn't make any function calls, doesn't refer to the value of any variable, and doesn't do any floating-point or pointer arithmetic, so it's an integer constant expression, and the compiler is required to evaluate it at compile time.
By contrast, if you were using this definition of MAX instead:
static inline size_t MAX(size_t a, size_t b)
{ return a > b ? a : b; }
then macro expansion would produce
U8* pBuffers[MAX(16, 8)];
and the expression inside the square brackets would be making a function call, so it wouldn't be an integer constant expression, or even a constant expression, and you would get a compile-time error.
(FYI, the rules in C++ are much more complicated; if you need to know about that, ask a new question.)
MACROS are always evaluated before the compilation process begins. So this code has nothing to worry about and it should work fine.
At the same time, this whole thing is the compiler dependent, I believe with gcc it will work fine. Maybe, for some bare-metal application, it may give a warning.
I'm writing some extremely repetitive code in C (reading XML), and I found that writing my code like makes it easier to copy and paste code in a constructor*:
something_t* something_new(void)
{
something_t* obj = malloc(sizeof(*obj));
/* initialize */
return obj;
}
What I'm wondering is, it is safe to use sizeof(*obj) like this, when I just defined obj? GCC isn't showing any warnings and the code works fine, but GCC tends to have "helpful" extensions so I don't trust it.
* And yes, I realize that I should have just written a Python program to write my C program, but it's almost done already.
something_t* obj = malloc(sizeof(*obj));
What I'm wondering is, it is safe to use sizeof(*obj)
like this, when I just defined obj?
You have a declaration consisting of:
type-specifier something_t
declarator * obj
=
initializer malloc(sizeof(*obj))
;
The C standard says in section Scopes of identifiers:
Structure, union, and enumeration tags have scope that begins just
after the appearance of the tag in a type specifier that declares the
tag. Each enumeration constant has scope that begins just after the
appearance of its defining enumerator in an enumerator list. Any other
identifier has scope that begins just after the completion of its
declarator.
Since obj has scope that begins just after the completion of its declarator, it is guaranteed by the standard that the identifier used in the initializer refers to the just defined object.
While we are giving the sizeof like this.
something_t* obj = malloc(sizeof(obj));
It will allocate the memory to that pointer variable as four bytes( bytes allocated to a pointer variable.)
something_t* obj = malloc(sizeof(*obj));
It will take the data type which is declared to that pointer.
For example,
char *p;
printf("%d\n",sizeof(p));
It will return the value as four.
printf("%d\n",sizeof(*p));
Now it will return value as one. Which is a byte allocated to the character. So when we are using the *p in sizeof it will take the datatype. I don't know this is the answer you are expecting.
It's safe. For example,
n = sizeof(*(int *)NULL);
In this case, NULL pointer access doesn't occur, because a compiler can caluculate the size of the operand without knowing the value of "*(int *)NULL" in run time.
The C89/90 standard guarantees the 'sizeof' expression is a constant one; it is translated into a constant (e.g. 0x04) and embedded into a binary code in compilation stage.
In C99 standard, the 'sizeof' expression is not always a compile-time constant, because of introducing variable length array. For example,
n = sizeof(int [*(int *)NULL]);
In this case, the value of "*(int *)NULL" needs to be known in run time to caluculate the size of 'int[]'.
I was just curious to know if it is possible to have a pointer referring to #define constant. If yes, how to do it?
The #define directive is a directive to the preprocessor, meaning that it is invoked by the preprocessor before anything is even compiled.
Therefore, if you type:
#define NUMBER 100
And then later you type:
int x = NUMBER;
What your compiler actually sees is simply:
int x = 100;
It's basically as if you had opened up your source code in a word processor and did a find/replace to replace each occurrence of "NUMBER" with "100". So your compiler has no idea about the existence of NUMBER. Only the pre-compilation preprocessor knows what NUMBER means.
So, if you try to take the address of NUMBER, the compiler will think you are trying to take the address of an integer literal constant, which is not valid.
No, because #define is for text replacement, so it's not a variable you can get a pointer to -- what you're seeing is actually replaced by the definition of the #define before the code is passed to the compiler, so there's nothing to take the address of. If you need the address of a constant, define a const variable instead (C++).
It's generally considered good practice to use constants instead of macros, because of the fact that they actually represent variables, with their own scoping rules and data types. Macros are global and typeless, and in a large program can easily confuse the reader (since the reader isn't seeing what's actually there).
#define defines a macro. A macro just causes one sequence of tokens to be replaced by a different sequence of tokens. Pointers and macros are totally distinct things.
If by "#define constant" you mean a macro that expands to a numeric value, the answer is still no, because anywhere the macro is used it is just replaced with that value. There's no way to get a pointer, for example, to the number 42.
No ,It's Not possible in C/C++
You can use the #define directive to give a meaningful name to a constant in your program
We can able to use in two forms.
Please : See this link
http://msdn.microsoft.com/en-us/library/teas0593%28VS.80%29.aspx
The #define directive can contain an object-like definition or a function-like definition.
Iam sorry iam unable to provide one more wink ... Please see the IBM links..since below i pasted linke link
u can get full info from above 2 links
There is a way to overcome this issue:
#define ROW 2
void foo()
{
int tmpInt = ROW;
int *rowPointer = &tmpInt;
// ...
}
Or if you know it's type you can even do that:
void getDefinePointer(int * pointer)
{
*pointer = ROW;
}
And use it:
int rowPointer = NULL;
getDefinePointer(&rowPointer2);
printf("ROW==%d\n", rowPointer2);
and you have a pointer to #define constant.