Why is sizeof considered an operator and not a function?
What property is necessary to qualify as an operator?
Because the C standard says so, and it gets the only vote.
As consequences:
The operand of sizeof can be a parenthesised type, sizeof (int), instead of an object expression.
The parentheses are unnecessary: int a; printf("%d\n", sizeof a); is perfectly fine. They're often seen, firstly because they're needed as part of a type cast expression, and secondly because sizeof has very high precedence, so sizeof a + b isn't the same as sizeof (a+b). But they aren't part of the invocation of sizeof, they're part of the operand.
You can't take the address of sizeof.
The expression which is the operand of sizeof is not evaluated at runtime (sizeof a++ does not modify a).
The expression which is the operand of sizeof can have any type except void, or function types. Indeed, that's kind of the point of sizeof.
A function would differ on all those points. There are probably other differences between a function and a unary operator, but I think that's enough to show why sizeof could not be a function even if there was a reason to want it to be.
It can be used as a compile-time constant, which is only possible if it's an operator rather than a function. For instance:
union foo {
int i;
char c[sizeof(int)];
};
Syntactically if it weren't an operator then it would have to be a preprocessor macro since functions can't take types as arguments. That would be a difficult macro to implement since sizeof can take both types and variables as an argument.
Because the C standard says so, and it gets the only vote.
And the standard is probably correct because sizeof takes a type and
In general, if either the domain or codomain (or both) of a function contains elements significantly more complex than real numbers, that function is referred to as an operator. Conversely, if neither the domain nor the codomain of a function contain elements more complicated than real numbers, that function is likely to be referred to simply as a function. Trigonometric functions such as cosine are examples of the latter case.
Additionally, when functions are used so often that they have evolved faster or easier notations than the generic F(x,y,z,...) form, the resulting special forms are also called operators. Examples include infix operators such as addition "+" and division "/", and postfix operators such as factorial "!". This usage is unrelated to the complexity of the entities involved.
(Wikipedia)
Because it's not a function. You can use it like that:
int a;
printf("%d\n", sizeof a);
Function does have entry point, code, etc. Function is to be run at runtime (or inlined), sizeof has to be determined at compile-time.
sizeof operator is compile time entity not runtime and don't need parenthesis like a function. When code is compiled then it replace the value with the size of that variable at compile time but in function after function gets execute then we will know the returning value.
Because:
when you pass a value to a function, the size of the object is not passed to the function, so a sizeof "function" would have no way of determining the size
in C, functions can only accept one type of argument; sizeof() needs to accept all sorts of differnet things (variables as well as types! You can't pass a type to a function in C)
calling a function involves making a copy of the arguments and other unnecessary overhead
There is small diference from function - value of sizeof is resolved on compile time, but not at runtime!
Because it is a compile-time operator that, in order to calculate the size of an object, requires type information that is only available at compile-time. This doesn't hold for C++.
sizeof() operator is a compile time would be occurrence. It can be used to determine the parameters or arguments.
Sizeof(), I think obviously it's both a function and an operator. Why? Because a function holds parentheses for entry at the stage of entry. But mainly also an operator cause operators are action character, therefore sizeof is an action statement that acts on the operand in the parentheses.
Related
This question already has answers here:
Why is sizeof considered an operator?
(10 answers)
Closed 8 years ago.
In c, we are using the sizeof() for getting the size of the datatypes. So
how it is defined. It is a macro or a function.
Because we can use that as two ways,
sizeof int
and
sizeof(int)
so how this is defined in header file.
It's neither. It's a built-in operator, whose value is computed at compile-time unless the argument is the name of a variable-length array (added in C99).
The parentheses that you often see are not part of the "call", since sizeof is not a function. They are part of the argument, and are only needed when the argument is a cast expression, i.e. the name of a type enclosed in parentheses.
I personally recommend against using sizeof with a type name as the argument whenever possible, since it's usually not needed, and creates a disconnect/de-coupling which can lead to errors.
Consider something like this:
float *vector = malloc(100 * sizeof(double));
The above, of course, contains a bug: if float is smaller than double, it will waste a lot of memory. It's easy to imagine ending up with something like the above, if vector started out as an array of double but was later changed to float. To protect aginst this, I always write:
float *vector = malloc(10 * sizeof *vector);
The above uses the argument *vector (an expression of type float) to sizeof, which is not a type name so no parentheses are needed. It also "locks" the size of the element to the pointer used to hold it, which is safer.
Sizeof is neither a macro nor a function.Its a operator which is evaluated at compile time.
Macros evaluated during pr-processing phase.
As pointed out by #Yu Hao Variable length arrays is the only exception.
For More Understanding solve this;
#include<stdio.h>
char func(char x)
{
x++;
return x;
}
int main()
{
printf("%zu", sizeof(func(3)));
return 0;
}
A) 1 B)2 C)3 D)4
From ISO/IEC9899
6.5.3.4 The sizeof operator
Constraints
1 The sizeof operator shall not be applied to an expression that has function type or an
incomplete type, to the parenthesized name of such a type, or to an expression that
designates a bit-field member.
So it is neither a macro nor a function.Its a operator!
and the way it is handled is a thing of the compiler.
But regarding to compile time and runtime determination the standard says:
Semantics
2 The sizeof operator yields the size (in bytes) of its operand, which may be an
expression or the parenthesized name of a type. The size is determined from the type of
the operand. The result is an integer. If the type of the operand is a variable length array
type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an
integer constant.
So it is even given by standard that it mus be determined on compile time excepting the VLA case.
Syntax
sizeof( type )
List sizeof expression
Both versions return a constant of type std::size_t.
Explanation
returns size in bytes of the object representation of type.
returns size in bytes of the object representation of the type, that
would be returned by expression, if evaluated.
The unary operator sizeof is used to calculate the size of any datatype, measured in the number of bytes required to represent the type.
In many programs, there are situations where it is useful to know the size of a particular datatype (one of the most common examples is dynamic memory allocation using the library function malloc). Though for any given implementation of C or C++ the size of a particular datatype is constant, the sizes of even primitive types in C and C++ are implementation-defined (that is, not precisely defined by the standard). This can cause problems when trying to allocate a block of memory of the appropriate size. For example, say a programmer wants to allocate a block of memory big enough to hold ten variables of type int. Because our hypothetical programmer doesn't know the exact size of type int, the programmer doesn't know how many bytes to ask malloc for. Therefore, it is necessary to use sizeof:
I wonder, when we create the function
int compar(const void *, const void *)
and we merely pass its name into one of the parameters of qsort and bsearch, how do those functions recognize said essentially random word (since we've never explicitly stated it is a function pointer, but rather an actual function) and use it as a parameter? Is there an explicit cast in the function declarations of qsort and bsearch or something?
This has nothing to do with the qsort and bsearch functions themselves, rather function names are implicitly converted by the compiler into function pointers as per the standard, C11 6.3.2.1 Language / Conversions / Other operands / Lvalues, arrays, and function designators:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
That means that, when you pass compar to qsort() (for example), it's the actual pointer to the function that gets passed, not some "essentially random word".
The reasons for implicitly treating a function identifier as its address lie long ago in the past but (and this whole section is supposition on my part, based on what I'd like to consider intelligent reasoning, but in no way definitive) it's likely to be because the value of a function makes no sense. With an identifier int i = 5;, it has a value (5), and you can also use &i to get it's address.
However, for functions, they don't really have values as such. You can call them to generate a value, xyzzy(), and you can get their address, &xyzzy, for later calling via a function pointer.
But they have no real intrinsic value separate from their address like the integer i does. So early compilers (pre-ANSI) simply allowed the shorthand xyzzy to mean &xyzzy. And, of course, since the original mandate of ANSI was to codify existing practice rather than create a new language, they preserved this behaviour.
If K&R had gone the other way and decided xyzzy should be a call to the function passing no parameters, the same as xyzzy(), the world would be a different place :-)
Sizeof operator is compile time operator. converts sizeof expression with constant result values during compile time. [Exception variadic templates c99]
Normally compiler fixes size for variables at compile time. for array n.
But when i print sizeof array it gives correct size?
is this code allots memory at compile time for n?
How sizeof is evaluated then?
how about the array a[] in function?
int fun(int n)
{
char a[n+3];
return sizeof(a);
}
int
main( )
{
int i;
while(i!=-1){
scanf("%d",&i);
int n[i];
printf("\nsize: %d %d\n",fun(3),sizeof n);
}
}
when i try this :
sizeof prints size of n correctly [(sizeof (int)) * i] but the function gives wrong results always 6?
How sizeof is implemented and calculates size (for float,int,...datatypes , variables, array, ...) ?
Any code is appreciated!
As you mention, sizeof calculations are normally made at compile time, by the compiler. That's not always true (for example, C99/C11 variable length arrays), but it's a reasonable approximation.
Since the compiler knows (or decides) the size of every type, it can just make a simple constant substitution during compilation.
For your examples, a and n are both variable length arrays, and the sizeof operator is applied at runtime.
From C11, Section 6.5.3.4 The sizeof and _Alignof operators, paragraph 2:
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
Editorial note: sizeof returns a size_t, not an int, so you should use a %zu format specifier instead of %d. Your compiler may warn you if you turn on the appropriate flags.
Wikipedia explains the implementation of sizeof pretty well, See here for detail.
It is the responsibility of compilers to implement the sizeof operator correctly for each target platform. In many cases, there will be an official Application Binary Interface (ABI) document for the platform, specifying formats, padding, and alignment for the data types, to which the compiler must conform. In most cases, sizeof is a compile-time operator, which means that during compilation sizeof expressions get replaced by constant result-values. However, sizeof applied to a variable length array, introduced in C99, requires computation during program execution.`
When the operand of sizeof is not a variable-length array (VLA), then it sizeof not really "calculate" anything. The result is immediately known to the compiler as a compile-time constant. That constant is substituted in place of sizeof during compilation.
If the operand is VLA, then the compiler simply generates code that retrieves the size information from the VLA itself. So, yes, in general case a typical implementation does store the size of the VLA inside the VLA itself. In your example that means that the memory allotted for a will also include a location to store the n + 3 value.
The compiler can, of course, optimize this evaluation in obvious cases and even replace it with compile-time constant in the most obvious cases. In your example the compiler might be smart enough not to retrieve the size from the array a, but instead immediately realize that the size is equal to n + 3.
Every C programmer can determine the number of elements in an array with this well-known macro:
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
Here is a typical use case:
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
However, nothing prevents the programmer from accidentally passing a pointer instead of an array:
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
On my system, this prints 2, because apparently, a pointer is twice as large as an integer. I thought about how to prevent the programmer from passing a pointer by mistake, and I found a solution:
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
This works because a pointer to an array has the same value as a pointer to its first element. If you pass a pointer instead, the pointer will be compared with a pointer to itself, which is almost always false. (The only exception is a recursive void pointer, that is, a void pointer that points to itself. I can live with that.)
Accidentally passing a pointer instead of an array now triggers an error at runtime:
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
Nice! Now I have a couple of questions:
Is my usage of assert as the left operand of the comma expression valid standard C? That is, does the standard allow me to use assert as an expression? Sorry if this is a dumb question :)
Can the check somehow be done at compile-time?
My C compiler thinks that int b[NUM_ELEMS(a)]; is a VLA. Any way to convince him otherwise?
Am I the first to think of this? If so, how many virgins can I expect to be waiting for me in heaven? :)
Is my usage of assert as the left operand of the comma expression valid standard C? That is, does the standard allow me to use assert as an expression?
Yes, it is valid as the left operand of the comma operator can be an expression of type void. And assert function has void as its return type.
My C compiler thinks that int b[NUM_ELEMS(a)]; is a VLA. Any way to convince him otherwise?
It believes so because the result of a comma expression is never a constant expression (e..g, 1, 2 is not a constant expression).
EDIT1: add the update below.
I have another version of your macro which works at compile time:
#define NUM_ELEMS(arr) \
(sizeof (struct {int not_an_array:((void*)&(arr) == &(arr)[0]);}) * 0 \
+ sizeof (arr) / sizeof (*(arr)))
and which seems to work even also with initializer for object with static storage duration.
And it also work correctly with your example of int b[NUM_ELEMS(a)]
EDIT2:
to address #DanielFischer comment. The macro above works with gcc without -pedantic only because gcc accepts :
(void *) &arr == arr
as an integer constant expression, while it considers
(void *) &ptr == ptr
is not an integer constant expression. According to C they are both not integer constant expressions and with -pedantic, gcc correctly issues a diagnostic in both cases.
To my knowledge there is no 100% portable way to write this NUM_ELEM macro. C has more flexible rules with initializer constant expressions (see 6.6p7 in C99) which could be exploited to write this macro (for example with sizeof and compound literals) but at block-scope C does not require initializers to be constant expressions so it will not be possible to have a single macro which works in all cases.
EDIT3:
I think it is worth mentioning that the Linux kernel has an ARRAY_SIZE macro (in include/linux/kernel.h) that implements such a check when sparse (the kernel static analysis checker) is executed.
Their solution is not portable and make use of two GNU extensions:
typeof operator
__builtin_types_compatible_p builtin function
Basically it looks like something like that:
#define NUM_ELEMS(arr) \
(sizeof(struct {int :-!!(__builtin_types_compatible_p(typeof(arr), typeof(&(arr)[0])));}) \
+ sizeof (arr) / sizeof (*(arr)))
Yes. The left expression of a comma operator is always evaluated as a void expression (C99 6.5.17#2). Since assert() is a void expression, no problem to begin with.
Maybe. While the C preprocessor doesn't know about types and casts and can't compare addresses you can use the same trick as for evaluating sizeof() at compile time, e.g. declaring an array the dimension of which is a boolean expression. When 0 it is a constraint violation and a diagnostic must be issued. I've tried it here, but so far have not been successful... maybe the answer actually is "no".
No. Casts (of pointer types) are not integer constant expressions.
Probably not (nothing new under the Sun these days). An indeterminate number of virgins of indeterminate sex :-)
consider the following snippet:
struct foo {
int a;
int b;
int c;
};
struct foo f;
printf("%u, %u\n", sizeof(struct foo), sizeof(f));
The code returns the same values, but I was wondering if sizeof() applied to variable is correct or this is just coincidence?
Thanks.
Both will and should indeed return the same value.
From MSDN:
The sizeof Operator
The sizeof operator gives the amount of storage, in bytes, required to store an object of the type of the operand. This operator allows you to avoid specifying machine-dependent data sizes in your programs.
sizeof unary-expression
sizeof ( type-name )
sizeof works with types and expressions. When you apply it to a type, the () are part of sizeof syntax: sizeof(type). When you apply it to an expression () are not part of sizeof syntax: sizeof expression.
So your second sizeof is not really "applied to a variable". It is applied to an expression (f). That expression consists of a single variable f enclosed into a redundant pair of (). You could also do without that redundant pair of () and use just sizeof f.
When sizeof is applied to an expression, it returns the size of the expression result (i.e. the size of the type that expression has). In your example both applications of sizeof are guaranteed to evaluate to the same value.
In fact, a good programming practice is to avoid sizeof(type) as much as possible, i.e. prefer to use sizeof expression. This makes your code more type-independent, which is always a good thing. Type names belong in declarations and nowhere else.
This is as expected, i.e. both will return the same value. This value is calculated at compile-time.
It's usually a good practice to use the variable in sizeof as you might later change the type and thus the size might change as well.
In general it is preferable to apply it to the variable. It will then remain correct if the type of the variable changes.