extern unsigned char pkt_data[];
Here what will be the pkt_data size. How do I know the pkt_data declaration?
All that the declaration says is that there's an array named pkt_data. The size is not specified there, and unless you're the one writing that line, the specifics of it should be left to the code that actually defines it (ie: reserves space for it).
It is extern declaration. It is declaration only, not definition.
It means pkt_data will be defined in some other file or some other modules being linked.
So, see the definition of pkt_data to see its size.
You have not declared the size, extern corresponds that you will define pkt_data[] some where else but only once. you cant get the size from an extern declaration.
This declaration
extern unsigned char pkt_data[];
as well as this one
unsigned char pkt_data[];
are incomplete.
It is not possible to determine the size of an incomplete type.
How do I know the pkt_data declaration?
You know it.
extern unsigned char pkt_data[];
is the declaration.
What is missing here is the definition.
To answer the question: Search it in the sources available. It you do not have access to the definition of pkt_data there is no chance to determine the size of pkt_data.
All we know is that the address of pkt_data would have the siez of a pointer. The following statement would be perfectly valid, btw:
size_t s = sizeof(&pkt_data);
Related
I found the below warning in map file , the struct extern declaration TYPE got changed in file2.c declaration. Below warning from IAR compiler,
Please let me know what is the impact of below type cast.
what is the memory size in file2.c while link time ?
I am trying to find impacts of this implementation not the solution
"struct_tag" to "uint8"
Warning[w6]: Type conflict for external/entry "Block_01", in module file2.c against external/entry in module file1.c; different basic types
/* In module file2.c: */
uint8 NvM_Block_01;
typedef unsigned char uint8;
/* In module file1.c: */
Block_01_T Block_01;
typedef struct Block_01_Tag Block_01_T;
typedef struct Block_01_Tag
{/* 4 bytes with CRC16 */
uint16 Data_01;
uint16 Crc_01;
}Block_01_T;
File1.c
Block_01_T Block_01 = {1234,1};
File2.c
extern unsigned char Block_01;
#define RPM_BLOCK (&Block_01)
Thanks
Damodaran
In file2.c, Block_01 is given type unsigned char, which is 1 byte in size. This will access the first byte of the structure Block_01_t, which will be part of Block_01_T.Data_01.
You have two variables of the same name. Block_01 and different types. This is not allowed. You need to change one of them.
Block_01_T Block_01 = {1234,1}; // in File1.c
extern unsigned char Block_01; // in File2.c
If you want both files to refer to the same variable, you can use.
extern Block_01_T Block_01; // in File2.c
The linker generally doesn't care about the size of object, just their addresses. The compiler reserves space in the object file that defines the object. In this case, the definition is in File1.c, which declares a structure containing two uint16, so it will most reserve at least 4 bytes.
According to the C standard, the consequences are undefined when you use Block_01 in File2.. But I think it's likely that it will be equivalent to giving it the same structure type declaration, and then using *(char *)(&Block_01).
This answer confused me.
If we have two lines in same .c file:
extern int c;
int c;
How is the first line of code a declaration and second a definition?
Aren't both declarations?
How these two lines differ?
The extern keyword is what makes the first line a declaration. It say "this variable exists somewhere". A line like that can appear in a header file.
The second line is a definition because the extern keyword is not present. If you were to have this line in a header file, two source files that include that header will both define that variable and linking those two files will result in a variable redefinition error.
When the program you're writing consists of multiple source files linked together, where some of the variables defined, for example, in source file file1.c need to be referenced in other source files, so this is the reason why using extern.
About your question how these lines differ:
extern int c;
int c;
A variable is defined when the compiler allocates the storage for the
variable while
A variable is declared when the compiler is informed that a variable
exists (and this is its type); it does not allocate the storage for
the variable at that point.
so only int c; is defined while extern int c; is declared .
A definition creates space for a variable:
int c;
Wherever you put this line, either local, global, this says that a new variable c of type int shall come to life.
extern int c;
A declaration says that there is somewhere else some variable c of type int. By using extern, you say that c is defined somewhere else. If you put only an extern declaration without a definition somewhere else, you will have a link error. Using extern is the equivalent of a forward declaration of a function:
/* declaration */
int f(int x);
vs.
/* definition */
int f(int x) {
return x*x;
}
The first means that there is somewhere a function f returning an int and accepting an int as parameter. The latter is the actual function, its code, which also works both as a declaration and a definition.
IMO, this declaration-vs-definition naming is confusing. I hardly remember which one is what, and I usually need to think about it. You should, however, understand the what extern means and what a forward declaration is.
Long story short, defining something means providing all of the necessary information to create that thing in its entirety. However, declaring something means providing only enough information for the computer to know it exists.
Edit: To be clearer: A definition both defines and declares, a declaration ONLY declares. When you are using the extern keyword by definition you are not defining anything. Your confusion stems from the understanding of extern.
I read the below piece of information in a microsoft article;
https://support.microsoft.com/en-us/kb/44463
The text below presents an example of a common programming mistake, that is, confusing an array and a pointer declaration:
Consider an application divided into several modules. In one module, declare an array as follows:
signed char buffer[100];
In another module, declare the following variables to access the array:
extern signed char *buffer; // FAILS
extern signed char buffer[]; // WORKS
If you view the code in the CodeView debugger, it indicates that the *buffer declaration produces a different address than the buffer[] declaration does.
But I can't understand why we cannot access that array using *buffer
and we can access it using buffer[] .
Someone please explain me what is the difference between those two types?
extern signed char buffer[];
is a chunk of memory that has an address.
extern signed char *buffer;
is a variable that may or may not point to a chunk of memory - it's a variable that contains an address that may or may not be valid.
In one module, you define an array of signed char of size 100 named buffer. This object will use 100 bytes of memory:
signed char buffer[100];
In another module, you declare buffer to be something else, a pointer to signed char, that is 4 or 8 bytes of memory that may hold the address of an array or that of a single char.
extern signed char *buffer;
The compiler only knows one module at a time, so it cannot check whether this declaration is consistent with the actual definition. It compiles code consistently with this declaration, emitting machine code that refers to an external symbol buffer that will be resolved at link time.
At link time, the linker does not know about types, it only relies on names. Therefore it resolves the references to buffer from one module with the actual address of the definition from the other module.
At runtime, you get undefined behaviour, because one module uses buffer as an array of signed char, which it is, and the other loads the value of a pointer from the same address, interpreting the bytes completely differently.
Declarations belong in header files and should always be included in the source file that actually defines the object declared in the header.
See these questions in the C FAQ List:
http://c-faq.com/aryptr/aryptr1.html
http://c-faq.com/aryptr/aryptr2.html
http://c-faq.com/aryptr/aryptrparam.html
This question is more about C linker than about C language.
Although there is a context where signed char *buffer and signed char buffer[] mean the same thing, extern is not one of them. Using extern asks the compiler to defer resolving of the external definition to linker. Linker has to be very particular about the difference between pointers and arrays, because the two have different structure in memory, and cannot be treated interchangeably.
Note that although these declarations are different to the linker, they do not change what a programmer could do with such an external array: in both cases you have no access to the size of the declared array (i.e. 100), the syntax to access array elements stays the same, and the pointer arithmetic remains the same.
The differences between
extern signed char *buffer;
extern signed char buffer[];
is the same as you would see when you have
signed char *buffer;
signed char buffer[100];
in a function.
I see the following differences:
Difference 1
When you have:
extern signed char *buffer;
you can use:
buffer = malloc(10);
When you have:
extern signed char buffer[];
you cannot do that.
Difference 2
In the first case, it is possible for buffer to be NULL. In the second case, it is not.
Difference 3
&buffer result in different types. For example, you can use:
printf("pointer 1: %p\n", &buffer+1);
in the first case but you cannot use that in the second case. For &buffer+1 to work in the second case, you'll have to know the size of the array.
A file has a series of void declarations used as void* as follows:
extern void __flash_rwdata_start;
...
initialize(&__flash_rwdata_start,
...
which are provided solely by the linker script as symbols referring to binary partitioning as follows (ie a pointer):
PROVIDE (__flash_rwdata_start = LOADADDR(.rwdata));
And this generates the following warning:
file.c:84:19: warning: taking address of expression of type 'void' [enabled by default]
As per the answer to Why has GCC started warning on taking the address of a void expression?, I've changed this as follows (the function which takes the pointers uses an unsigned long* anyway):
extern unsigned long __flash_rwdata_start;
Now it occurs to me that the original definition had an implication of zero (or undefined) size, whereas the current definition does not, and unlike the answer to Why has GCC started warning on taking the address of a void expression? there is no "real underlying data type" that makes any logical sense.
Essentially I've defined a pointer that is valid, but does not point to a valid value, and thus it would be invalid to dereference.
Is there a safer or preferable way to avoid the warning, but without the idea of space being allocated, that can't be dereferenced?
One idea that comes to mind is to make the object's type be an incomplete struct, like:
extern struct never_defined __flash_rwdata_start;
This way the address will be valid, but, as long as the type is never defined, not dereferenceable.
For completeness, the usual way besides "void" (which doesn't conform to C11 at least), is
extern char __flash_rwdata_start[];
I do like Tom's answer better though.
Just started with K & R and on the 2nd chapter, there is the line:
Declarations list the variables to be
used and state what type they have and
perhaps what their initial values are.
So:
int x = 42 is a definition.
and int x is a declaration but also a definition since every definition is a declaration.
But when we assign an intial value like K & R say, doesn't that make the declaration a definition?
You confuse two things:
A declaration states (declares) what an object's* type, name and scope is
A definition defines what a object's content is
* object as in: variable, function etc., not an OOP object.
A definition is hence very often also a declaration, since you cannot define what is in an object when you do not state what the type of the object is. Easiest to remember is just: "Every definition is a declaration, but not every declaration is a definition"
For variables
There is only 1 way to declare without defining the variable:
extern typeX variable_name
This tells the compiler that there is a variable called variable_name with type typeX, but not where to get it.
Every other way to declare a variable is also a definition, since it tells the compiler to reserve space for it and perhaps give it an initial value.
The difference is much clearer in structs and functions:
For Structs
A declaration:
struct some_struct{
int a;
int b;
}
This declares some_struct to the compiler with a and b as struct variables both with type int.
Only when you define them space is reserved and you can use them:
void foo(){
struct some_struct s;
s.a = 1; // For this to work s needs to be defined
}
For functions:
The difference is much more clear
declaration:
// This tells the compiler that there is a function called "foo" that returns void and takes void arguments
void foo();
A definition could be like the one above (in the struct part)
Basically you can say that a declaration simply tells the compiler that there is somewhere a variable with that name and type. It does produce any code, and in C, this has to be done with the extern keyword on variables. Function prototypes (without implementation) are also mere declarations, and don't need the extern keyword, but you can still provide it.
A definition produces code, e.g. allocates memory on the stack or heap for a variable, or the body for methods.
In that sense, both of your statments are definitions, and any definition is also a delcaration.
I think that might by a mistake by K&R...