In C, I have read that half-initialized arrays will be filled with zeros for the rest of the elements (irrespective of integer or char arrays).
E.g.:
int arr[10] = {3};
arr[4] will be 0 if initialized and a junk value if not initialized.
My question is, will the above work for all C compilers (or) this appending of zeros might occur or not occur depending on the compiler option? I am working in Code composer studio (TI's IDE). I want to ensure that this will work for all cases and all compilers.
The behaviour is specified by the C Standard. But if you are worried about the behaviour of your specific compiler, why not write a test?
This is according to the C standard, and any compiler following the C standard must do this. However, not all compilers are 100% standard compliant, and you'll have to check if yours does this or not, if you're unsure.
Variables, located in data segment (global and unit scope), are automatically initialised to all zeros.
Stack variables (function and block scope) are filled with garbage unless explicitly initialised, even partially initialised. In case of partial initialisation, reminder is zeroed.
That's by the C standard and all compilers must adhere to it.
This should work irrespective of which compiler you are using.
If you want to be sure that your code will work with all compilers you should initialize all your array elements just like it:
int arr[10] = {3,0,0,0,0,0,0,0,0,0};
If the number of elements of your array is too high (100 or 10000) the best solution becomes to initialize it dynamicaly at the runtime.
It is dependent on the design of the compiler. Normally compilers support it and some may support via some flags during compilation or other options. Some may not support it. It is better to check with the concerned compiler support regd the compatibility with C standard. I think Code Composer Studio IDE(TI DSP processors) support group might give you the exact answer.
Karthik Balaguru
The language spec specifies default behavior, however not all compilers implement the defined behavior. A good example of this is that Visual Studio 2008 is the first version of the Microsoft C/C++ compiler that will call the default constructor on uninitialized elements in an array which has been the defined behavior of array initialization since at least the C++ 98 spec.
If you are worried about how your code will behave running on multiple compilers it is better to be safe than sorry and explicitly initialize all values.
Related
This is in reference to this question
How to implement the c malloc/realloc functions properly?
where the accepted answer mentions that a char array can be used to model a pool of arbitrary memory.
However one of the comments to that accepted answer states
A char array that doesn't have allocated storage duration can only be
aliased by a character type. In other words it cannot and it should
not be used as arbitrary memory
Is this correct? If so, then what could be used? I'd like to avoid using alloc or any specific OS calls - so I'm symmetrical with that question.
There are different problems around. First as shown by #Magisch's answer the related question was returning a dangling pointer causing Undefined Behaviour and generally execution errors.
The second one is related to the #^*# (censorship here) strict aliasing rule. Common compilers produce correct code when you use a character array as a large buffer to allocate any type from it, provided you ensure correct alignment. After all, this is the way they have to implement the malloc, realloc, and free routines. And as they are part of the hosted environment (C standard library), the compiler developpers are not masochist enough to fordib that usage.
But the C standard is a bit more strict here. You should read my own answer here to a similar question and particularly #EOF's comment to it:
You cannot parcel of parts of an object declared as char [] into objects of other types (except character types), because they do have a declared type... which means technically you can't implement malloc() in pure C
I believe the issue he pointed out was that if you allocate a char type array statically and then compile your library with a modern, desktop-like C compiler like gcc, you cannot easily convert the contents of that area to another type. Because then the compiler would perform optimizations based on pointer aliasing and screw everything up, see "the strict aliasing rule".
Simply assure that your compiler does not use strict aliasing and you'll be fine. For example, none of the common embedded systems compilers on the market does this.
With gcc you'd compile as -fno-strict-aliasing. Might be good to always enable warnings for code that would cause such problems -Wstrict-aliasing.
As a side note, uint8_t makes far more sense to use as generic type, because unlike char, it is completely unambiguous: it has no signedness and the size is well-known.
Aliasing refers to the strict aliasing rule that governs how the compiler is allowed to use registers. If you have pointers of different type referring to the same memory location, then writing done through one pointer type may not be noticed when reading through the other pointer type because the compiler is allowed to cache the data in registers.
When you implement a memory pool, this problem is usually moot, because the pool implementation doesn't read/write to the memory.
If you want arbitrary types, then the safest bet is a union. Not only will it "beat" the strict aliasing rule, it will also ensure correct alignment. Remember that malloc and friends ensure alignment suitable for any type while auto doesn't.
The issue is alignment. On processors that have alignment restrictions, a char array may not start at an address suitable for storing larger objects, like int or double.
So to be safe, you need to make sure the char array is aligned properly for any type.
If you're using a C11 compiler, then you can force alignment like this
#include <stddef.h>
#include <stdalign.h>
_Alignas(max_align_t) char buffer[SIZE];
For older compilers, __attribute__((aligned(SIZE))) may be a solution. Otherwise, you need to look for a #pragma that forces alignment.
And as discussed in various comments/answers, you should definitely disable the strict aliasing optimization with the -fno-strict-aliasing option. If that option (or the equivalent) doesn't exist, then you need to determine the optimization level that relies on the strict aliasing rule, and only use a lower optimization level.
So for example,
int aaa(unsigned int par1, unsigned int par2){
int array[par1*par2];
return 0;
}
I tried compiling the code that contains this, and it compiled well and had no run-time issue - the array was properly created.
But I know that this is basically declaring a dynamic array in static array declaration fashion. What may go wrong with this declaration? Will there be a compiler issue in a different compiler?
This is correct as per the 1999 C standard. The 2011 standard changed it to be an optional feature, which in practice means that all C11 compilers will support it except for MSVC.
Before 1999 some compilers offered this as a non-standard extension.
Here is a link to StackOverflow search for other questions on this topic.
But I know that this is basically declaring a dynamic array in static array declaration fashion.
This is called VLA (Variable-Length Array). This array is not static - it is placed in automatic memory (also known as "the stack").
What may go wrong with this declaration?
It may overflow the stack when the size of the array exceeds a certain limit specific to your system.
Will there be a compiler issue in a different compiler?
This is a C99 feature, so compiler that do not support C99 may fail to compile this code.
I believe this is a C99-only feature. It's called VLA (variable-length arrays).
The C++0x does't support VLA:
https://groups.google.com/forum/#!topic/comp.std.c++/K_4lgA1JYeg
But some compilers might not be strictly compliant with the standard.
I have a bit of code copied from an unknown source:
int Len=0;
printf("Please input the length of vector");
scanf("%d",&Len);
float x[Len],y[Len],sig[Len];
Now normally I believe that arrays cannot be initialized during runtime with a variable. However, this does allegedly compile. Problem is that again I do not know the compiler. Is there a C variant where this is legal? The compiler I am using, IAR C, does not like it.
I am also seeing arrays indexed from 1 rather than 0, which suggests this is translated from something like Pascal originally. Any opinions?
Now normally I believe that arrays cannot be initialized during runtime with a variable.
That has been true before C99 standard. It is also illegal in C++ (although some compilers, such as gcc, offer this as an extension).
Is there a C variant where this is legal?
Any C99 compiler will do.
I am also seeing arrays indexed from 1 rather than 0
This is OK as well, as long as you are fine allocating an extra element, and not using element at index zero.
Note: since accessing an element past the end of an array is undefined behavior, an invalid program may appear to work and produce the desired result in your test runs. If you suspect that some array indexes may be off by one, consider running your program under a memory profiler, such as valgrind, to see if the program has hidden errors related to invalid memory access.
This was a feature introduced in C99 and are called VLAs(Variable Length Arrays). These arrays are also indexed starting from 0 not 1 and ending at length-1(Len-1 in your case) just like a normal array.
In C99 this is valid and called a VLA-Array.
This is called a Variable Length Array (VLA) and is a C99 feature.
If your compiler does not recognise it on it's own then try switching C standards
Try:
--std=c99
-std=c99
--std=gnu99
-std=gnu99
The manual page of your compiler will be able to tell you the exact flag.
I know that I'm not supposed to do this in C90, and it's a rather basic stuff.
char name[strlen(s)];
ArrayLength.c:11: warning: ISO C90 forbids variable length array ‘name’
Did they want me to specifically use malloc? I'm just curios here about the logic behind it.
It's forbidden because C90 doesn't support variable-length arrays (VLAs). It's really as simple as that.
Your options are:
Declare a fixed-length array that can cope with the maximum string length you want to work with.
Dynamically-allocate the array (using malloc).
Work with a compiler that offers VLAs a non-standard language extension, e.g. GCC. (I don't recommend this, because it means you'll end up writing non-portable code.)
Use C99 instead, where VLAs are supported. Note that VLAs are allocated on the stack, which can cause all sorts of issues if you run out of stack space (unlike with malloc, there's no concept of being able to check that the allocation was successful).
[Note: If you're allocating an array in order to make a copy of s, you'll need to use strlen(s)+1 as the size (remember the null terminator).]
It's not that "they" don't want you to do it, it's simply not part of the language (or rather, wasn't prior to 1999). The standard workaround is to use malloc or alloca. (alloca is essentially identical to variable length array allocation, but is not a standard function, so it may not be available on all systems of interest. Also, some people have strong objections to it's use, but they tend to object strong to variable-length arrays for the same reasons.)
This warning points to the usage of a GNU gcc extension is a serious portablity problem.
The code is illegal, because the value of strlen(s) is not known at compile time. GNU gcc provides an extension for automatic arrays that allocate based on run time values; but relying on these makes the code out of compliance with the standard.
If the value of strlen(s) isn't known until run-time then one can bring the code into compliance by either converting to performing the allocation/deallocation explicitly on conventions arrays, or by using STL containers.(e.g. std::vector).
It's a matter of the language having restrictions for the presumed convenience of the
compiler and its intended runtime environment.
In a discussion, a colleague told me that he never uses enum because he experienced that some C-compilers don't cope with the enum statement correctly.
He couldn't remember which compiler exactly had problems but among the problems, there were errors when doing something like
enum my_enum{
my_enum_first = 5;
my_enum_second = 10;
};
i.e. initializing enum values instead of letting the compiler do the automatic assignment. Another one was that the compiler decides for itself how big the enum is and therefore you could have unpredictable behavior for sizeof my_enum when compiling your code under various platforms.
To get around that, he told me to better use #defines to define the constant elements. But especially for using doxygen it's quite handy to have an enum (e.g. as function parameter) because in the generated documentation, you could simply click on my_enum and directly jump to the description of my_enum.
Another example would be code completion, where your IDE tells you what you could specify as valid parameters for functions. I know that – as long as you're compiling the code as C-code – that there's no type-safety (i.e. I could also specify 5 instead of my_enum_first), so the use of an enum seems to be a more cosmetic thing.
The question is: do you know any compilers that have limitations regarding the usage of enum?
Edit 1:
Regarding the environment: we are developing for various embedded platforms, so there could also be a compiler for some obscure micro-controller...
Edit 2:
He could tell me that the KEIL C51 compiler didn't play well with enums. Are there any experiences with current versions of the C51 compiler?
Compilers are free to choose the size of an enum based on its range of possible values. This only really becomes an issue if you're exposing enums in your API, and users of your code may be using a different compiler or build options.
In this case, confusion can be caused by the calling code passing in a 16-bit value, for example, and the receiving code expecting it to be 32 bits. If the top 16 bits of the passed-in value are left uninitialized, then bad things will happen.
You can work around this kind of issue by including a dummy entry in your enum to enforce a minimum size.
For example:
typedef enum {
FirstValue = 12,
SecondValue = 25,
DummyValue = 65536 // force enum to be greater than 16 bits
} MyEnum;
I'm pretty sure that a compiler that doesn't play nice with enum is an invalid compiler - enum is specified in the standard, so a failure to implement it means the compiler shouldn't technically be used to compile C (For the record, the scope of enumeration types is discussed in 6.2.1 and defined as a type in 6.2.5 (of C99), so one would assume that it's a valid part of the standard from thereon in)!
So no, I don't know of any such compilers.