Just wondering what is the soundest way to allocate memory and fread()
array data from a file in C.
First, an explanation:
int32_t longBuffer;
Now, when freading in the longBuffer, the code could go as:
fread(&longBuffer, sizeof(longBuffer), 1, fd); //version 1
fread(&longBuffer, sizeof(int32_t), 1, fd); //version 2
Among the two, I would say that version 1 is more bug-safe, since if the type of longBuffer
changes (let's say to int16_t
), one does not have to worry about forgetting to update the fread()
's sizeof()
with the new type.
Now, for an array of data, the code could be written as:
//listing 1
int8_t *charpBuffer=NULL; //line 1
charpBuffer = calloc(len, sizeof(int8_t)); //line 2
fread(charpBuffer, sizeof(int8_t), len, fd); //line 3
However, this exhibits the problem exposed in the first example: one has to worry about not forgetting to synchronize the sizeof(<type>)
instructions when changing the type of charpBuffer
(let's say, from int8_t*
to int16_t*
).
So, one may attempt to write:
fread(charpBuffer, sizeof(charpBuffer[0]), len, fd); //line 3a
as a more bug-safe version. This should work since, after the allocation on line 2, writing charpBuffer[0]
is perfectly valid.
Also, one could write:
fread(charpBuffer, sizeof(*charpBuffer), len, fd); //line 3b
However, trying to do the same for memory allocation, such as:
charpBuffer = calloc(len, sizeof(charpBuffer[0])); //line 2a
while better in syntax, exhibits undefined behaviour because, at this stage, writing charpBuffer[0]
results into dereferencing a NULL pointer. Also, writing:
charpBuffer = calloc(len, sizeof(*charpBuffer)); //line 2b
exhibits the same problem.
So, now the questions:
Are the lines of code "line 2b" and "line 3b" correct (ignore the undefined behaviour for this question) or there are some tricks that I miss w.r.t. their "wiser" counterparts such as "line 2a/3a" and "line 2/3"?
What would be the most bug-safe way to write the "listing 1" code, but avoiding any form of undefined behaviour?
EDITS (in order to clarify some aspects):
The discussion took wrong direction. The question of compile time vs run time is one thing (and I would like to have a standard guarantee for this one, too, but it is not the topic). And the question of undefined behaviour for sizeof(NULL dereferencing) is another. Even if at compile time, I am not convinced that this is guaranteed by the standard to not result in UB. Does the standard provide any guarantees?
From C99 6.5.4.3.2 (emphasis mine):
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.
That the operand is "not evaluated" means that it's perfectly safe to access sizeof(charBuffer[0])
or sizeof(*charBuffer)
, because those expressions are only used for their types. Example 3 on the same page goes on to explicitly document the sizeof array / sizeof array[0]
idiom for computing the number of elements in an array without any mention or implication that it wouldn't be valid for empty arrays.