【问题标题】:C99 | (BItfield) Struct in a Struct don't work to be choosen with name1.name2.variableC99 | (BItfield)结构中的结构不能与 name1.name2.variable 一起选择
【发布时间】:2019-06-07 07:31:54
【问题描述】:

如何解决这个错误?我想要一个数组,我可以在其中扫描“学生”的数据并因此使用结构。问题是,另一个结构中的位域结构失败了。

有什么方法可以解决这个问题,而不改变代码的大部分结构?只想修复,可以选择位域(日,月等)。

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

#define MAX 10
#define MAXCHAR 30

char comma;

struct date {
    unsigned int day:5;         
    unsigned int month:4;
    unsigned int year:11;   //funktioniert bis yr 2047;
};

struct student {
        unsigned long matriculation_number;
        char first_name[MAXCHAR];
        char last_name[MAXCHAR];
        struct date birthdate;
}Student[MAX];

/*
void scan_student(void) {
b
} */

int main(void) {

    int i = 0;
    printf("------------------------------\nGeben Sie alle benötigten Daten ein\n");
    printf("Vorname: ");
    fgets(Student[i].first_name, MAXCHAR, stdin);

    printf("Nachname: ");
    fgets(Student[i].last_name, MAXCHAR, stdin);

    printf("Matrikelnummer: ");
    scanf(" %lu", &Student[i].matriculation_number);

    printf("Geburtstdatum (DD.MM.YYYY): ");
    scanf(" %u%c%u%c%u", &Student.birthdate.day, &comma, &Student.birthdate.month, &comma, &Student.birthdate.year);
    printf("\n");


    return EXIT_SUCCESS;
}

错误日志:

student.c: In function ‘main’:
student.c:42:26: error: cannot take address of bit-field ‘day’
     scanf(" %u%c%u%c%u", &Student[i].birthdate.day, &comma, &Student[i].birthdate.month, &comma, &Student[i].birthdate.year);
                          ^
student.c:42:61: error: cannot take address of bit-field ‘month’
     scanf(" %u%c%u%c%u", &Student[i].birthdate.day, &comma, &Student[i].birthdate.month, &comma, &Student[i].birthdate.year);
                                                             ^
student.c:42:98: error: cannot take address of bit-field ‘year’
 &Student[i].birthdate.day, &comma, &Student[i].birthdate.month, &comma, &Student[i].birthdate.year);

【问题讨论】:

  • 为什么使用位域而不仅仅是ints?除此之外,编译器错误似乎很清楚。对于scanf,您必须传递您指定的类型。你可以做类似int tmp; scanf("%d", &amp;tmp); Student[i].birthdate.day = tmp;的事情。
  • 这个任务的想法是使用位域和结构
  • 但它必须在没有“tmp”步骤的情况下工作......
  • 你不能获取位域的地址;没有指向位域的指针。因此,您不能将指向位域的指针传递给scanf() 以供其使用。您必须输入适当大小的局部变量(short 或更大的年份;char 或更大的其他字段),将指针传递给scanf(),然后将结果传递给通过赋值的位域。如果中间变量是禁止使用的,则不能在结构中使用位域。我顺便观察到您的结构将占用 32 位;您可以使用 2 个 char 字段和一个 short 来代替。
  • 这些约束从何而来?它们不是很合理。

标签: c arrays struct c99


【解决方案1】:

struct date 是使用位域定义的,因此它没有在字节边界上对齐。因为它不在字节边界上,所以您不能使用 &amp; 运算符获取它的地址。尝试重新定义struct date,如下所示。

struct date {
    unsigned char day;
    unsigned char month;
    unsigned short year;
}

这有一个额外的好处是允许您将年份存储到 65535 而不是 2047。

【讨论】:

  • 您在 30491 年有什么安排? :D
  • @JonathanLeffler 30491 对我来说会很忙
  • 我知道这行得通,但任务是为“日期”使用位域 - 没有办法吗?
  • @Bifrost:无法将位字段传递给scanf(),因为正如 C11 标准在脚注 124 中所说(至 §6.7.2.1 Structure and union specifiers):124)一元 @987654327 @ (address-of) 运算符不能应用于位域对象;因此,没有指向位域对象的指针或数组。 因此,您不能通过scanf() 和家族直接输入struct date 中的位域。
【解决方案2】:

虽然您不能将位域成员传递给 scanf,但您可以将临时成员传递给 scanf,然后将它们分配给位域而不会出现问题:

unsigned char day = 0, month = 0;
unsigned short year = 0;
scanf(" %hhu%c%hhu%c%hu", &day, &comma, &month, &comma, &year);
Student.birthdate.day = day;
Student.birthdate.month = month;
Student.birthdate.year = year;

请注意,这确实涉及缩小,因此您可能有一个成功的 scanf,然后无法将其完整值存储在位域中。

鉴于进一步的 cmets 指出不允许您使用 tmp 步骤,这对于设置此任务的人来说是完全不合理的,因此您根本不能使用 scanf。但是,您可以单独读取字符串,然后使用strtoul 或类似方法将数字标记转换为可以直接分配给位域的返回值。我真的不建议这样做,但如果它是作业或类似的要求,它是可能的。

根据要求:C11 specification 第 7.21.6.1 节第 7 段描述了此示例中使用的长度修饰符 hhh。这些允许指定要读取的整数类型的长度,其中hhchar 的长度,h 是short 的长度。将这些与d i o u xX 结合使用允许指定所有内置整数类型以由(f)scanf 读取。

【讨论】:

  • 请查看 POSIX scanf() 以找出为什么 %udaymonth 值的错误转换规范 - 这些需要相同的修复;以及为什么 year 值也是错误的(需要稍微不同的修复)。
  • 非常正确,我应该在发布答案之前解决这个问题。感谢您指出。
  • 我是否可以推荐包含指向scanf() 的POSIX 规范或C11 §7.21.6.2 The fscanf function 规范的链接,或scanf() 的Linux 手册——或等效页面?以及对hhh 长度修饰符的快速解释。
猜你喜欢
  • 2016-03-02
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 2018-10-14
相关资源
最近更新 更多