[英]How can I use the size of an external array at compile time in C?
I have the following snippet from some foo.c
file:我有一些foo.c
文件的以下片段:
unsigned char foo[] = {1, 2, 3, 4};
void copy_foo(unsigned char *dest)
{
memcpy(dest, foo, sizeof(foo));
}
And I want to declare a bar
array in another C file ( main.c
) that has the same size as foo
, to hold the output of copy_foo
:我想在另一个 C 文件( main.c
)中声明一个与foo
大小相同的bar
数组,以保存 copy_foo 的copy_foo
:
int main(void)
{
unsigned char bar[?];
copy_foo(bar);
return 0;
}
Is it possible to get access to sizeof(foo)
from main.c
at compile time, so that it could be used to declare the bar
array?是否可以在编译时从main.c
访问sizeof(foo)
,以便可以用来声明bar
数组?
The usual "solution" to this problem is to use some sort of heap allocation to allocate memory at runtime, but I am looking for a static, compile time solution, as some embedded systems prohibit the use of dynamic allocation.这个问题的通常“解决方案”是在运行时使用某种堆分配来分配 memory,但我正在寻找 static,编译时解决方案,因为某些嵌入式系统禁止使用动态分配。
Of course, I can add #define FOO_SIZE 4
to foo.h
, but then if foo
changes FOO_SIZE
will have to be manually changed as well.当然,我可以将#define FOO_SIZE 4
添加到foo.h
,但是如果foo
更改FOO_SIZE
也必须手动更改。
Is this possible?这可能吗?
Add this to the header file:将此添加到 header 文件中:
// foo.h
extern const size_t foo_len;
And add this right below the definition of the array:并将其添加到数组定义的正下方:
// foo.c
const size_t foo_len = sizeof foo / sizeof foo[0];
And then you can use foo_len
in your main function or wherever you want, without having to worry about manually maintaining that value.然后你可以在你的主 function 或任何你想要的地方使用foo_len
,而不必担心手动维护该值。
This, however, is the only way to make this work in C, as the lengths of static arrays are lost after compiling, which happens before linking.然而,这是在 C 中进行这项工作的唯一方法,因为 static arrays 的长度在编译后丢失,这发生在链接之前。 This means you have to add similar lines for every array you want to use their predefined lengths.这意味着您必须为要使用其预定义长度的每个数组添加类似的行。
Here's the solution I found, for anyone interested.这是我找到的解决方案,适合任何感兴趣的人。 If anyone has a better solution I would still be interested to see it:)如果有人有更好的解决方案,我仍然有兴趣看到它:)
main.c
: main.c
:
#include "foo.h"
int main(void)
{
unsigned char bar[FOO_SIZE];
copy_foo(bar);
return FOO_SIZE;
}
foo.h
: foo.h
:
#define FOO (unsigned char []){1, 2, 3, 4}
#define FOO_SIZE sizeof(FOO)
void copy_foo(unsigned char *dest);
foo.c
: foo.c
:
#include <string.h>
#include "foo.h"
unsigned char foo[] = FOO;
void copy_foo(unsigned char *dest)
{
memcpy(dest, foo, FOO_SIZE);
}
This works thanks to "Compound literals" , which allow us to define "anonymous" arrays.这要归功于“复合文字” ,它允许我们定义“匿名”arrays。 FOO
is defined as one of those compound literals, and it can be used to initialize the foo
array. FOO
被定义为这些复合文字之一,它可用于初始化foo
数组。 The interesting part is that it could also be used inside a sizeof
, so the line:有趣的部分是它也可以在sizeof
中使用,所以行:
unsigned char bar[FOO_SIZE];
evaluates to:评估为:
unsigned char bar[sizeof((unsigned char []){1, 2, 3, 4})];
which is perfectly legal.这是完全合法的。
Now to prove that this really evaluates to 4 at compile time , and that it doesn't add extra copies of the array to the data section:现在证明这确实在编译时计算为 4 ,并且它不会将数组的额外副本添加到数据部分:
I compiled with:我编译:
gcc main.c foo.c -S
In foo.s
:在foo.s
:
.globl foo
.data
.type foo, @object
.size foo, 4
foo:
.ascii "\001\002\003\004"
There is no such array in main.s
so the compiler didn't copy the array. main.s
中没有这样的数组,所以编译器没有复制数组。 This makes sense, because the array is declared inside a sizeof, so the compiler should be smart enough to optimize it and replace it with a 4.这是有道理的,因为数组是在 sizeof 中声明的,所以编译器应该足够聪明,可以优化它并用 4 替换它。
To check that the value is available at compile time, I returned it as the return value of main
, which compiled to:为了检查该值在编译时是否可用,我将它作为main
的返回值返回,编译为:
movl $4, %eax
movq -8(%rbp), %rdx
xorq %fs:40, %rdx
je .L3
call __stack_chk_fail@PLT
.L3:
leave
.cfi_def_cfa 7, 8
ret
The return value is passed through the eax register, and we can see that it got the immediate value of 4, which proves that the compiler knew what that value is.返回值通过 eax 寄存器传递,我们可以看到它得到了立即数 4,这证明编译器知道那个值是什么。
You can use just a static array with accessor.您可以只使用带有访问器的 static 阵列。
// foo.h
static unsigned char _foo[] = {1,2,3,4};
#define FOO_SIZE (sizeof(_foo))
unsigned char *foo(void); // if you ever need to use _foo
void copy_foo(unsigned char*);
// foo.c
unsigned char *foo(void) {
return _foo;
}
void copy_foo(unsigned char *dest) {
memcpy(dest, foo(), FOO_SIZE);
}
// main.c
#include "foo.h"
int main(void) {
unsigned char bar[FOO_SIZE];
copy_foo(bar);
return FOO_SIZE;
}
Just make sure you never ever use _foo
anywhere in your code except in foo.c
, because it's static
and exists in each source file that includes foo.h
.只要确保你永远不会在代码中的任何地方使用_foo
,除了foo.c
,因为它是static
并且存在于每个包含foo.h
的源文件中。 Compiler will remove unused static global variables from all source files leaving only a single _foo
in foo.c
file.编译器将从所有源文件中删除未使用的 static 全局变量,在foo.c
文件中只留下一个_foo
。
If the array is defined in a different module, it must be declared in a common header file with a specified length for every module to use or check consistency:如果数组在不同的模块中定义,则必须在具有指定长度的通用 header 文件中声明,以便每个模块使用或检查一致性:
foo.h foo.h
extern unsigned char foo[4];
foo.c foo.c
#include "foo.h"
// if the size in foo.h is not correct, this will cause an error
unsigned char foo[] = { 1, 2, 3, 4 };
void copy_foo(unsigned char *dest) {
memcpy(dest, foo, sizeof(foo));
}
main.c main.c
#include "foo.h"
int main() {
unsigned char bar[sizeof(foo) / sizeof(*foo))];
copy_foo(bar);
return 0;
}
If the length of the array cannot be specified in the header file, you could define an external variable foo_len
, but it will not be a constant expression, so bar
will be a VLA (variable length array, a C99 feature made optional in C17).如果数组的长度不能在 header 文件中指定,你可以定义一个外部变量foo_len
,但它不会是一个常量表达式,所以bar
将是一个 VLA(可变长度数组,C99 特性在 C17 中成为可选) .
foo.h foo.h
extern unsigned char foo[]; // optional
extern int foo_len;
foo.c foo.c
#include "foo.h"
// if the size in foo.h is not correct, this will cause an error
unsigned char foo[] = { 1, 2, 3, 4 };
int foo_len = sizeof(foo) / sizeof(*foo);
void copy_foo(unsigned char *dest) {
memcpy(dest, foo, sizeof(foo));
}
main.c main.c
#include "foo.h"
int main() {
unsigned char bar[foo_len];
copy_foo(bar);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.