【问题标题】:Is it possible to pass an array of a predefined size to a C function so that its size could be retrieved with `sizeof` in that function?是否可以将预定义大小的数组传递给 C 函数,以便可以在该函数中使用“sizeof”检索其大小?
【发布时间】:2014-12-09 23:55:25
【问题描述】:

在下面的示例中,是否可以使用这样的签名声明 test() 以便打印6?出于样式和可读性的目的,我希望这样做,因此很明显该函数需要一个正好 6 个字符的数组,并且它实际上可以通过 sizeof 获取此信息。

#include <stdio.h>

void test( char foo[ 6 ] )
{
  printf( "%zu\n", sizeof( foo ) ); // Prints 8 as it's a pointer now, but I want 6 as in an array
}

int main()
{
  char foo[ 6 ];
  printf( "%zu\n", sizeof( foo ) ); // Prints 6, which is what I want
  test( foo );
  return 0;
}

到目前为止,我能想到的最好的是:

typedef char Foo[ 6 ];
void test( Foo foo )
{
  printf( "%zu\n", sizeof( Foo ) ); // Works, but it doesn't even use foo, and I want to get the size information from foo! What if I change the signature of the function later? I would have to update this line too, which is something I'd like to avoid
}

【问题讨论】:

  • 这段代码真的可以编译吗?无论如何,只需将您想要的大小作为附加参数传递给方法,或扫描空值或类似的东西。
  • 您不能将数组传递给 C 中的函数。就像,完全一样。您所能做的就是传递指针,例如指向 6 个 char 的数组的指针。尽管@RobertHarvey 提到了任何理智的人如何在 C 中处理它。
  • 我希望6 只出现一次,所以如果需要更改,只有一个地方可以这样做。我当然可以定义它,但这有点过于冗长了。
  • OP,难道你真的想使用 C++ 而不是 C?
  • 我只想传递一个普通的指针。随着编译器跟踪它指向 6 个元素,而不是任意数量。那有什么问题?如果这是不可能的,很好,我很乐意接受这个作为答案。

标签: c arrays


【解决方案1】:

是的,有可能:

#include <stdio.h>

void test(char (*foo)[6]) // "declare foo as pointer to array 6 of char" 
{
  printf("%zu\n", sizeof(*foo)); // mind the asterisk
}

int main(void)
{
  char foo[6];
  test(&foo); // mind the ampersand
  return 0;
}

比较 cdecl.org(“C 胡言乱语 ↔ 英语”)为


另一个选项是包装数组。但是,如果您不喜欢引用/取消引用,那么这个具有附加成员访问权限的解决方案可能也不是您想要的:

#include <stdio.h>

typedef struct
{
  char data[6];
} char_6_array_t;

void test(char_6_array_t foo)
{
  // prints "6: abcdef"
  printf("%zu: %.*s\n", sizeof(foo.data), (int) sizeof(foo.data), foo.data);
}

int main(void)
{
  char_6_array_t foo = { {"abcdef"} };

  // Depending on the ABI, this prints 6, 8, or possibly 16:
  printf("%zu\n", sizeof(foo));

  test(foo);
  return 0;
}

【讨论】:

  • 这样做没有意义,如果你硬编码大小,那么就使用那个大小。
  • 是的,它看起来没那么有用,但它是一个巧妙的技巧。我不知道这是可能的。
  • 他希望函数签名包含 6 以提高样式和可读性。这是一个很好的答案
  • @dragonroot 您要求提供支持“出于样式和可读性目的”的解决方案。现在您有另一个条件来避免“解决方案引入了额外的引用/取消引用操作”。建议更新您的帖子以包含该内容,而不是仅在本地评论中,或在不添加该内容的情况下对答案进行评分。
  • 如何用printf("%.*s\n", (int) sizeof(array), array);打印数组的有趣示例
【解决方案2】:

并非没有一些杂技。

有一些方法可以使其工作,或者使用您问题中的全局变量,或者使用 Kay 提出的解决方案。但是 C 语言不会按值将整个数组作为函数参数传递。你的test 函数只接收一个指向char 的指针,编译器不会告诉你指针可能指向的数组大小。

其他一些语言,比如 C++,会为你处理这类事情。但是在 C 中,您只需要自己跟踪大小,一种或另一种方式。一种常见的方法是在函数中添加另一个参数,在其中传入数组的大小。

在你给出的函数原型中:

void test( char foo[ 6 ] )

我认为不幸的是编译器只是忽略了6,尽管您可能会争辩说这没有多大意义。对于多维数组,编译器注意你给出的大小,除了第一个,所以foo[][6] 有效,并且有必要告诉编译器你数组的每一行结束。 (见this question。)

另一种解决方法是使用这样的结构:

struct array {
    char *a;   // pointer to your real array
    size_t s;  // how many elements your array has
};

您可以将其中一种结构传递给您的函数,然后从中读取大小。

【讨论】:

  • 为了清楚起见,我不想按值传递数组。我想传递一个指向 6 个字符数组的指针,并且我希望函数的签名包含该信息。此外,我希望可以在函数中从签名中检索此大小信息。虽然我可以写void fn( char foo[ 6 ] ),但我无法从函数体内检索到6。顺便说一句,我给你写这个评论只是为了在整个线程中至少有一个人理解我。其余的人群似乎没有,这让我很难过。感谢您的参与:)
  • @dragonroot 奇怪的是,C 语言允许您指定foo[6],而它完全忽略了 6。我在回答中添加了一些内容。也许某些语言律师知道为什么foo[6] 是被允许的,因为它显然与foo[] 没有任何不同。
  • 没错。至于你提到的解决方法,它增加了额外的间接和额外的内存使用,而我只是希望编译器在编译时给我这个值 6 :)
  • “编译器确实会注意你给出的大小,除了第一个”。这就是问题所在,对于数组,唯一的大小是第一个。
猜你喜欢
  • 2020-12-09
  • 2021-04-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 2013-05-17
  • 1970-01-01
相关资源
最近更新 更多