2 PAT排名汇总 (25分)注意 不要使用 long long int

本文介绍了一种算法,用于合并多个考点的计算机程序设计能力考试(PAT)成绩,并生成总排名表。通过两次排序和遍历,确保了考生的最终排名正确无误,解决了longlong类型可能导致的排序错误问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计算机程序设计能力考试(Programming Ability Test,简称PAT)旨在通过统一组织的在线考试及自动评测方法客观地评判考生的算法设计与程序设计实现能力,科学的评价计算机程序设计人才,为企业选拔人才提供参考标准(网址http://www.patest.cn)。

每次考试会在若干个不同的考点同时举行,每个考点用局域网,产生本考点的成绩。考试结束后,各个考点的成绩将即刻汇总成一张总的排名表。

现在就请你写一个程序自动归并各个考点的成绩并生成总排名表。

输入格式:

输入的第一行给出一个正整数N(≤100),代表考点总数。随后给出N个考点的成绩,格式为:首先一行给出正整数K(≤300),代表该考点的考生总数;随后K行,每行给出1个考生的信息,包括考号(由13位整数字组成)和得分(为[0,100]区间内的整数),中间用空格分隔。

输出格式:

首先在第一行里输出考生总数。随后输出汇总的排名表,每个考生的信息占一行,顺序为:考号、最终排名、考点编号、在该考点的排名。其中考点按输入给出的顺序从1到N编号。考生的输出须按最终排名的非递减顺序输出,获得相同分数的考生应有相同名次,并按考号的递增顺序输出。

输入样例:

2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

输出样例:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

全部输入后再排序最大 测试点是答案错误不是超时内存超限。。。

我也一时半会儿查不出来

补充:错误很可能是long long 类型导致的,longlong不是精准数据类型,sort可能出错误,改为string 即可通过。

改正后代码

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
struct stu{
	string id;
	int score;
	int kc;
	int kcpm;
	int zpm;
};
bool cmp0(stu s1,stu s2){
	if(s1.kc==s2.kc){
		return s1.score>s2.score;
	}else return s1.kc<s2.kc;
}
bool cmp1(stu s1,stu s2){
	if(s1.score!=s2.score){
		return s1.score>s2.score;
	}return s1.id<s2.id;
}
vector<stu>st;
int main(){
	long long int n;
	cin>>n; 
	for(int i=0;i<n;i++){
		int p;
		cin>>p;
		for(int j=0;j<p;j++){
			string a;
			int b;
			cin>>a>>b;
			stu s;
			s.id=a;
			s.score=b;
			s.kc=i+1;
			st.push_back(s);
		}
	}
	sort(st.begin(),st.end(),cmp0);
	int count=1;
	for(int i=0;i<st.size();i++){
		if(i>0&&st[i].kc!=st[i-1].kc){
			count=1;
		}
		st[i].kcpm=count++;
		if(i>0&&st[i].kc==st[i-1].kc&&st[i].score==st[i-1].score){
			st[i].kcpm=st[i-1].kcpm;
		}
	}
	sort(st.begin(),st.end(),cmp1);
	cout<<st.size()<<endl;
	count=1;
	for(int i=0;i<st.size();i++){
		st[i].zpm=count++;
		if(i>0&&st[i].score==st[i-1].score){
			st[i].zpm=st[i-1].zpm;
		}
		cout<<st[i].id<<" "<<st[i].zpm<<" "<<st[i].kc<<" "<<st[i].kcpm<<endl;
	}
	return 0;
}

 

改正前 long long int 数据代码

 

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
struct stu{
	long long int id;
	int score;
	int kc;
	int kcpm;
	int zpm;
};
bool cmp0(stu s1,stu s2){
	if(s1.kc!=s2.kc){
		return s1.kc>s2.kc;
	}else {
		return s1.score>s2.score;
	}
}
bool cmp1(stu s1,stu s2){
	if(s1.score!=s2.score){
		return s1.score>s2.score;
	}return s1.id<s2.id;
}
vector<stu>st;
int main(){
	long long int n;
	cin>>n; 
	for(int i=0;i<n;i++){
		int p;
		cin>>p;
		for(int j=0;j<p;j++){
			long long a,b;
			cin>>a>>b;
			stu s;
			s.id=a;
			s.score=b;
			s.kc=i+1;
			st.push_back(s);
		}
	}
	sort(st.begin(),st.end(),cmp0);
	int count=1;
	for(int i=0;i<st.size();i++){
		if(i>0&&st[i].kc!=st[i-1].kc){
			count=1;
		}
		st[i].kcpm=count++;
		if(i>0&&st[i].kc==st[i-1].kc&&st[i].score==st[i-1].score){
			st[i].kcpm=st[i-1].kcpm;
		}
	}
	sort(st.begin(),st.end(),cmp1);
	cout<<st.size()<<endl;
	count=1;
	for(int i=0;i<st.size();i++){
		st[i].zpm=count++;
		if(i>0&&st[i].score==st[i-1].score){
			st[i].zpm=st[i-1].zpm;
		}
		cout<<st[i].id<<" "<<st[i].zpm<<" "<<st[i].kc<<" "<<st[i].kcpm<<endl;
	}
	return 0;
}

 超了一个大佬答案过了

https://blog.csdn.net/xiang_6/article/details/78759565链接在这里

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 30000+7, INF = 0x7f7f7f7f;
int T, n;
struct node {
    string s;
    int sc, id, st, fst;
}a[maxn];
bool cmp(node a, node b) {
    if(a.sc == b.sc) return a.s < b.s;
    return a.sc > b.sc;
} 
int main() {
    scanf("%d", &T);
    int cnt = 0;
    for(int i = 1; i <= T; ++i) {
        scanf("%d", &n);
        string s; int x;
        for(int j = 0; j < n; ++j) {
            cin >> s >> x;
            a[cnt+j].s = s; a[cnt+j].sc = x; a[cnt+j].id = i;
        }
        sort(a+cnt, a+cnt+n, cmp);
        a[cnt].st = 1;
        for(int j = 1; j < n; ++j) {
            if(a[cnt+j].sc == a[cnt+j-1].sc) a[cnt+j].st = a[cnt+j-1].st;
            else a[cnt+j].st = j+1;
        }
        cnt += n;
    }
    sort(a, a+cnt, cmp);
    cout << cnt << endl;
    a[0].fst = 1;
    cout << a[0].s << " " << a[0].fst << " " << a[0].id << " " << a[0].st << endl;
    for(int i = 1; i < cnt; ++i) {
        if(a[i].sc == a[i-1].sc) a[i].fst = a[i-1].fst;
        else a[i].fst = i+1;
        cout << a[i].s << " " << a[i].fst << " " << a[i].id << " " << a[i].st << endl;
    }
    return 0;
}
/*
2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85
*/

 

<think>首先,用户的问题是关于计算一个C语言结构体的大小。结构体是`T_PAT_INFO`,包含多个成员,包括基本数据类型和枚举类型。枚举类型是`E_SEX`、`E_BLOOD_TYPE`、`E_PAT_TYPE`,但用户没有提供这些枚举的具体定义。在计算结构体大小时,我需要假设这些枚举的大小。通常,在C语言中,枚举的大小取决于编译器,但通常是`int`的大小,即4字节(在32位系统上)或4字节(在64位系统上,枚举通常还是4字节)。为了通用性,我应该假设这些枚举是`int`类型,所以每个4字节。 结构体的大小受内存对齐(alignment)的影响。不同的编译器有不同的对齐规则,但通常遵循最大对齐要求。成员的对齐通常基于其类型的大小。 列出结构体的所有成员及其类型和大小(假设标准x86系统,32位或64位,其中`int`是4字节,`long`是4字节或8字节,但`unsigned long`在Windows 64位是4字节,Linux 64位是8字节?用户没有指定系统,所以我应该假设常见环境。在许多系统中,`unsigned long`是4字节或8字节。为了安全,我应该考虑对齐。 在标准C中,`unsigned int`是4字节,`int`是4字节,`unsigned long`通常是4字节或8字节。`unsigned char`是1字节。 枚举:假设每个枚举是4字节。 数组:`unsigned char surName[21]`(因为20+1=21),同样其他数组。 现在,计算结构体大小需要考虑对齐。编译器会插入填充字节来对齐成员。 步骤: 1. 列出所有成员及其大小和自然对齐。 - `unsigned int itemMask;`:大小4字节,对齐4字节。 - `unsigned int patId;`:大小4字节,对齐4字节。 - `unsigned long bornDate;`:假设4字节或8字节。在许多系统上,`long`是4字节(32位系统)或8字节(64位系统)。但为了准确,我应该指定一个假设。用户没有指定,所以我应该考虑常见情况。假设是32位系统,其中`long`是4字节。或者64位系统?在Linux x86_64,`long`是8字节;在Windows x86_64,`long`是4字节。这很混乱。或许我假设`unsigned long`是4字节,以简化。或者,我可以说明它依赖于系统。 为了通用性,我应该计算两种场景:一种是`long`为4字节,另一种是8字节。 但用户可能期望一个具体的答案。或许在医疗或嵌入式系统中,系统是32位的。我可以假设所有类型都是标准大小:`int`和`enum`是4字节,`long`是4字节(32位系统),`char`是1字节。 检查成员: - `bornDate` 和 `admitDate` 是 `unsigned long`。 在32位系统中,通常是4字节;在64位Linux,是8字节;在64位Windows,是4字节。 为了简单,假设是4字节,因为许多系统使用ILP32或类似。 实际上,在C标准中,大小是依赖于实现的。但既然用户没有指定,我应该使用常见假设。 或许在问题上下文中,系统是32位的,因为结构体中有许多`unsigned int`和`int`。 我将假设: - `unsigned int`: 4字节 - `int`: 4字节 - `unsigned long`: 4字节(假设32位系统) - `enum` (E_SEX, etc.): 4字节 - `unsigned char`: 1字节 数组大小: - `surName[21]`: 21字节 - `name[21]`: 21字节 - `docSurName[21]`: 21字节 - `docName[21]`: 21字节 - `caseNo[21]`: 21字节 - `address[2]`: 2字节 (1+1) - `tel[2]`: 2字节 - `note[2]`: 2字节 - `bPace`: `unsigned char`, 1字节 现在,计算结构体大小,考虑对齐。 起始地址:0 1. `itemMask`: unsigned int, 4字节, 地址0-3 (对齐4,所以从0开始) 2. `patId`: unsigned int, 4字节, 地址4-7 (下一个地址是4,对齐4,ok) 3. `bornDate`: unsigned long, 假设4字节, 地址8-11 (下一个地址8,对齐4,ok) 4. `admitDate`: unsigned long, 4字节, 地址12-15 5. `weight`: int, 4字节, 地址16-19 6. `height`: int, 4字节, 地址20-23 7. `sexType`: E_SEX, 假设4字节, 地址24-27 8. `bloodType`: E_BLOOD_TYPE, 4字节, 地址28-31 9. `patType`: E_PAT_TYPE, 4字节, 地址32-35 10. `bPace`: unsigned char, 1字节, 地址36 现在,下一个是 `surName[21]`。但 `bPace` 在地址36,是1字节,`surName` 是char数组,对齐1字节,所以可以从地址37开始。 但 `surName` 大小21字节,地址37到57。 然后 `name[21]`: 地址58到78 `docSurName[21]`: 79 to 99 `docName[21]`: 100 to 120 `caseNo[21]`: 121 to 141 现在 `address[2]`: 142 to 143 `tel[2]`: 144 to 145 `note[2]`: 146 to 147 结构体结束于147字节。 但我们需要检查对齐。结构体本身的对齐要求是其成员的最大对齐要求。最大对齐是4字节(来自int, long, enum)。 在地址36,`bPace` 是1字节,没有填充,因为下一个成员 `surName` 是char数组,对齐1,所以不需要填充。 所有char数组对齐1,所以不需要额外填充。 结构体大小应该是148字节?地址从0到147,所以大小是148字节。 确认地址: - 0-3: itemMask - 4-7: patId - 8-11: bornDate - 12-15: admitDate - 16-19: weight - 20-23: height - 24-27: sexType - 28-31: bloodType - 32-35: patType - 36: bPace (1 byte) - 37-57: surName[21] (21 bytes, 37 to 57 inclusive? 57-37+1=21, yes) 地址37到57是21字节:37,38,...,57 (57-37+1=21) 然后 name[21]: 58 to 78 docSurName[21]: 79 to 99 docName[21]: 100 to 120 caseNo[21]: 121 to 141 address[2]: 142 to 143 tel[2]: 144 to 145 note[2]: 146 to 147 所以最后一个字节是147,大小是148字节 (since 0 to 147 inclusive is 148 bytes). 但在结构体中,可能有填充在末尾以对齐结构体,如果用于数组。 结构体的大小必须是其对齐要求的倍数。最大对齐是4字节(因为int, long, enum 都是4字节对齐),所以总大小应该是4的倍数。 148是4的倍数吗?148 / 4 = 37, 是。 所以大小是148字节。 但等一下,`bPace` 是 unsigned char, 1字节,在地址36。下一个 surName 在37,没有填充,因为char数组不需要对齐大于1。 类似地,所有后续成员都是char数组或小数组,不需要额外对齐。 在 `patType` (4字节) 之后,地址35结束,`bPace` 在36,是1字节对齐,ok。 然后 surName 从37开始。 但 36 是 4 的倍数,所以 `bPace` 对齐正确。 之后,没有填充问题。 但是,`address`, `tel`, `note` 各是2字节,但它们是unsigned char[2],所以对齐1字节,没问题。 所以总大小148字节。 但用户有 `address[1+1]` 即 [2],同样 `tel[2]`, `note[2]`,所以2字节各。 在代码中,是 `unsigned char address[1+1];` 所以 size 2. 但在计算中,我认为是正确的。 现在,如果 `unsigned long` 是8字节呢?假设64位系统,其中long是8字节。 然后: - bornDate: 8字节,对齐8字节 - admitDate: 8字节,对齐8字节 其他类似。 起始地址0。 itemMask: unsigned int, 4字节, 地址0-3 patId: unsigned int, 4字节, 地址4-7 bornDate: unsigned long, 8字节, 对齐8字节。下一个地址是8,是8的倍数,所以地址8-15 admitDate: 8字节, 地址16-23 weight: int, 4字节, 地址24-27 height: int, 4字节, 地址28-31 sexType: enum, 4字节, 地址32-35 bloodType: enum, 4字节, 地址36-39 patType: enum, 4字节, 地址40-43 bPace: unsigned char, 1字节, 地址44 现在,surName[21]: 从地址45开始(因为44+1=45),到65(45+20=65? 45 to 65 inclusive is 21 bytes: 65-45+1=21) 计算:索引从0,size 21: 地址 start to start+20. 所以 surName: 45 to 65 name: 66 to 86 docSurName: 87 to 107 docName: 108 to 128 caseNo: 129 to 149 address: 150 to 151 tel: 152 to 153 note: 154 to 155 结束于155。 大小:156字节(0到155 inclusive)。 最大对齐是8字节(来自long),156 / 8 = 19.5,不是整数,156 mod 8 = 4,所以需要填充到160字节(160/8=20)。 在结构体末尾,添加填充使其大小为最大对齐的倍数。 所以大小应为160字节。 在代码中,我们可以使用sizeof运算符来获取大小。 但既然用户要求计算,我应该提供计算。 在回答中,我应该说明假设。 或许用户期望在32位系统下的答案。 另一个点:枚举的大小。在C中,枚举的大小可以是1、2、4字节等,取决于值。但通常,编译器使用int大小,4字节。我假设4字节。 同样,对于数组,如surName[21],大小21字节。 在结构体中,成员顺序影响填充。例如,在第一个场景中,当bPace在36,然后surName在37,没有填充,但如果编译器优化,可能会重排,但通常不重排。 在第二个场景中,当long是8字节时,在patId之后(地址7结束),bornDate需要8对齐,所以从地址8开始,但地址7之后是8,是8的倍数,所以没有填充,ok。 在weight之后(地址27结束),height在28,是4的倍数,ok。 在patType之后(地址43结束),bPace在44,是1的倍数,ok。 然后surName从45开始。 但45是1的倍数,char数组对齐1,所以没问题。 结束于155,但结构体对齐要求是8,所以填充到160。 现在,在用户的问题中,有E_SEX等枚举,我假设4字节。 但为了准确,我应该写一个C程序来计算大小。 既然用户要求代码,我可以提供C代码来打印大小。 用户说“计算下面结构体大小”,然后“请你详尽的给出我解决方案,尽可能的给出我代码并解释这些代码”。 所以,我可以写一个C程序定义结构体和枚举,然后使用sizeof。 但枚举没有定义,所以我需要定义它们。 用户没有提供枚举定义,所以我必须假设或定义虚拟枚举。 例如: typedef enum { MALE, FEMALE } E_SEX; typedef enum { A, B, AB, O } E_BLOOD_TYPE; typedef enum { INPATIENT, OUTPATIENT } E_PAT_TYPE; 大小应该相同,只要编译器使用相同大小。 在代码中,我可以定义这些枚举。 然后使用sizeof(T_PAT_INFO)。 在解释中,说明依赖系统。 在回答中,我可以提供代码和输出。 但用户可能期望手动计算。 按照流程:回答问题-给出解释。 首先,回答问题:结构体大小依赖于系统,但常见情况下是X或Y。 然后提供代码。 最后相关问题。 在代码中,使用markdown格式。 定义枚举和结构体,然后打印大小。 例如: ```c #include <stdio.h> // 定义枚举类型 typedef enum { MALE, FEMALE } E_SEX; typedef enum { A, B, AB, O } E_BLOOD_TYPE; typedef enum { INPATIENT, OUTPATIENT } E_PAT_TYPE; typedef struct t_pat_info { unsigned int itemMask; unsigned int patId; unsigned long bornDate; unsigned long admitDate; int weight; int height; E_SEX sexType; E_BLOOD_TYPE bloodType; E_PAT_TYPE patType; unsigned char bPace; unsigned char surName[20 + 1]; unsigned char name[20 + 1]; unsigned char docSurName[20 + 1]; unsigned char docName[20 + 1]; unsigned char caseNo[20 + 1]; unsigned char address[1 + 1]; unsigned char tel[1 + 1]; unsigned char note[1 + 1]; } T_PAT_INFO; int main() { printf("Size of T_PAT_INFO: %zu bytes\n", sizeof(T_PAT_INFO)); return 0; } ``` 然后,解释代码定义枚举和结构体,然后打印大小。 但大小依赖于编译器和系统。 在32位系统,unsigned long 可能是4字节,在64位可能是8字节。 在代码中,我可以添加打印类型大小来澄清。 例如: ```c printf("Size of unsigned long: %zu\n", sizeof(unsigned long)); // 其他 ``` 但在主回答中,我可以运行在假设系统上。 或许在解释中,手动计算两种场景。 既然用户要求解决方案,我可以提供典型值。 在相关问题中,可以问关于对齐的问题。 现在,回答问题: 结构体的大小取决于平台和编译器,但我们可以计算典型情况。假设枚举类型的大小为4字节(如同int),并且考虑内存对齐。 在32位系统(其中unsigned long为4字节): - 手动计算大小约为148字节,考虑对齐后无填充问题。 在64位系统(其中unsigned long为8字节): - 大小约为156字节,但由于最大对齐为8字节,可能需要填充至160字节。 为了准确,我们可以编写C程序来获取大小。 以下是一个C程序,用于输出结构体的大小: ```c #include <stdio.h> // 定义枚举类型 typedef enum { MALE, FEMALE } E_SEX; typedef enum { A, B, AB, O } E_BLOOD_TYPE; typedef enum { INPATIENT, OUTPATIENT } E_PAT_TYPE; typedef struct t_pat_info { unsigned int itemMask; unsigned int patId; unsigned long bornDate; unsigned long admitDate; int weight; int height; E_SEX sexType; E_BLOOD_TYPE bloodType; E_PAT_TYPE patType; unsigned char bPace; unsigned char surName[20 + 1]; // 21 bytes unsigned char name[20 + 1]; // 21 bytes unsigned char docSurName[20 + 1]; // 21 bytes unsigned char docName[20 + 1]; // 21 bytes unsigned char caseNo[20 + 1]; // 21 bytes unsigned char address[1 + 1]; // 2 bytes unsigned char tel[1 + 1]; // 2 bytes unsigned char note[1 + 1]; // 2 bytes } T_PAT_INFO; int main() { printf("Size of T_PAT_INFO: %zu bytes\n", sizeof(T_PAT_INFO)); // 打印一些类型的大小以作参考 printf("Size of unsigned long: %zu\n", sizeof(unsigned long)); printf("Size of enum: %zu\n", sizeof(E_SEX)); // 假设所有枚举大小相同 return 0; } ``` 编译并运行此程序将在特定系统上给出确切大小。 解释: - 该程序定义了枚举类型和结构体 `T_PAT_INFO`。 - 在 `main` 函数中,使用 `sizeof` 运算符打印结构体的大小。 - 还打印了 `unsigned long` 和枚举的大小以供参考。 - 大小取决于编译器、目标平台及其对齐规则。例如,在32位Windows系统上,`unsigned long` 是4字节,结构体大小可能为148字节;在64位Linux系统上,`unsigned long` 是8字节,结构体大小可能为160字节(带填充)。 在手动计算中,考虑对齐规则: - 每个成员必须从其大小的倍数地址开始(例如,4字节类型从4的倍数地址开始)。 - 结构体大小必须是其最大成员对齐的倍数。 对于32位系统(4字节对齐): - 成员顺序排列,除 `bPace` 后可能无填充外,基本无填充。 - 总大小:148字节(如先前计算)。 对于64位系统(8字节对齐): - `bornDate` 和 `admitDate` 为8字节,需要8字节对齐。 - 计算后,无内部填充时大小为156字节,但末尾可能填充至160字节以满足对齐要求。 相关问题: 关于结构体大小和对齐的问题。 例如: 1. 什么是结构体填充(padding)? 2. 如何减少结构体大小? 3. 为什么需要内存对齐? 4. 使用 `#pragma pack` 的效果是什么? 格式:§§相关问题§§: 1. ... 2. ... 3. ... 4. ...</think>### 回答:结构体大小计算 结构体 `T_PAT_INFO` 的大小取决于系统架构、编译器及其内存对齐规则。内存对齐是为了提高访问效率,编译器会在成员之间或末尾插入填充字节(padding),使每个成员从其类型大小的倍数地址开始。结构体总大小必须是其最大成员对齐要求的倍数。 #### 关键假设: - **枚举类型大小**:`E_SEX`、`E_BLOOD_TYPE`、`E_PAT_TYPE` 在大多数系统中等同于 `int` 类型,因此我假设每个枚举占 **4 字节**(常见于 32 位和 64 位系统)。 - **数据类型大小**: - `unsigned int`:4 字节 - `int`:4 字节 - `unsigned char`:1 字节 - `unsigned long`:大小依赖于系统。在 32 位系统(如 Windows ILP32 或 Linux x86)中通常为 **4 字节**;在 64 位系统(如 Linux x86_64)中通常为 **8 字节**(Windows x64 中 `unsigned long` 仍为 4 字节,但为通用性考虑 64 位 Linux 情况)。 - **数组大小**:根据定义,数组大小固定: - `surName[20 + 1]` = `surName[21]`(21 字节) - 同理 `name[21]`、`docSurName[21]`、`docName[21]`、`caseNo[21]` 各 21 字节 - `address[1 + 1]` = `address[2]`(2 字节) - `tel[2]`、`note[2]` 各 2 字节 - **对齐规则**:成员的对齐要求为其自身大小(例如 4 字节类型必须从 4 的倍数地址开始)。结构体总大小必须是最大成员对齐的倍数(本例中最大对齐为 `unsigned long` 的大小,即 4 或 8 字节)。 - **编译器**:假设默认对齐规则(无 `#pragma pack` 等指令)。 #### 手动计算大小 我计算两种常见场景:32 位系统(`unsigned long` 为 4 字节)和 64 位 Linux 系统(`unsigned long` 为 8 字节)。成员顺序固定,按声明排列。 ##### 场景 1: 32 位系统(`unsigned long` = 4 字节) - 最大对齐要求:4 字节(来自 `unsigned int`、`int`、`enum`、`unsigned long`)。 - 成员地址和填充计算(起始地址 0): - `itemMask` (4 字节):地址 0-3(对齐 4,无填充) - `patId` (4 字节):地址 4-7(对齐 4,无填充) - `bornDate` (4 字节):地址 8-11(对齐 4,无填充) - `admitDate` (4 字节):地址 12-15(对齐 4,无填充) - `weight` (4 字节):地址 16-19(对齐 4,无填充) - `height` (4 字节):地址 20-23(对齐 4,无填充) - `sexType` (4 字节):地址 24-27(对齐 4,无填充) - `bloodType` (4 字节):地址 28-31(对齐 4,无填充) - `patType` (4 字节):地址 32-35(对齐 4,无填充) - `bPace` (1 字节):地址 36(对齐 1,无填充) - `surName[21]` (21 字节):地址 37-57(对齐 1,无填充) - `name[21]` (21 字节):地址 58-78(对齐 1,无填充) - `docSurName[21]` (21 字节):地址 79-99(对齐 1,无填充) - `docName[21]` (21 字节):地址 100-120(对齐 1,无填充) - `caseNo[21]` (21 字节):地址 121-141(对齐 1,无填充) - `address[2]` (2 字节):地址 142-143(对齐 1,无填充) - `tel[2]` (2 字节):地址 144-145(对齐 1,无填充) - `note[2]` (2 字节):地址 146-147(对齐 1,无填充) - 总大小:地址 0 到 147 共 148 字节。 - 结构体末尾对齐:148 是最大对齐(4 字节)的倍数(148 ÷ 4 = 37),无末尾填充。 - **结论:148 字节**。 ##### 场景 2: 64 位 Linux 系统(`unsigned long` = 8 字节) - 最大对齐要求:8 字节(来自 `unsigned long`)。 - 成员地址和填充计算(起始地址 0): - `itemMask` (4 字节):地址 0-3(对齐 4,无填充) - `patId` (4 字节):地址 4-7(对齐 4,无填充) - `bornDate` (8 字节):地址 8-15(地址 8 是 8 的倍数,对齐 8,无填充) - `admitDate` (8 字节):地址 16-23(对齐 8,无填充) - `weight` (4 字节):地址 24-27(对齐 4,无填充) - `height` (4 字节):地址 28-31(对齐 4,无填充) - `sexType` (4 字节):地址 32-35(对齐 4,无填充) - `bloodType` (4 字节):地址 36-39(对齐 4,无填充) - `patType` (4 字节):地址 40-43(对齐 4,无填充) - `bPace` (1 字节):地址 44(对齐 1,无填充) - `surName[21]` (21 字节):地址 45-65(对齐 1,无填充) - `name[21]` (21 字节):地址 66-86(对齐 1,无填充) - `docSurName[21]` (21 字节):地址 87-107(对齐 1,无填充) - `docName[21]` (21 字节):地址 108-128(对齐 1,无填充) - `caseNo[21]` (21 字节):地址 129-149(对齐 1,无填充) - `address[2]` (2 字节):地址 150-151(对齐 1,无填充) - `tel[2]` (2 字节):地址 152-153(对齐 1,无填充) - `note[2]` (2 字节):地址 154-155(对齐 1,无填充) - 无填充时总大小:地址 0 到 155 共 156 字节。 - 结构体末尾对齐:156 不是最大对齐(8 字节)的倍数(156 ÷ 8 = 19.5)。编译器会添加 4 字节填充,使地址扩展到 159(156 到 159 为填充),总大小为 160 字节(160 ÷ 8 = 20)。 - **结论:160 字节(含 4 字节末尾填充)**。 #### 通过代码获取确切大小 由于大小依赖于系统,最佳方法是编写 C 程序使用 `sizeof` 运算符输出大小。以下代码定义枚举和结构体,并打印大小。代码使用 `%zu` 格式说明符打印 `size_t` 类型。 ```c #include <stdio.h> // 定义枚举类型(假设值域,大小通常为4字节) typedef enum { MALE, FEMALE } E_SEX; typedef enum { A, B, AB, O } E_BLOOD_TYPE; typedef enum { INPATIENT, OUTPATIENT } E_PAT_TYPE; typedef struct t_pat_info { unsigned int itemMask; unsigned int patId; unsigned long bornDate; unsigned long admitDate; int weight; int height; E_SEX sexType; E_BLOOD_TYPE bloodType; E_PAT_TYPE patType; unsigned char bPace; unsigned char surName[20 + 1]; // 21 bytes unsigned char name[20 + 1]; // 21 bytes unsigned char docSurName[20 + 1]; // 21 bytes unsigned char docName[20 + 1]; // 21 bytes unsigned char caseNo[20 + 1]; // 21 bytes unsigned char address[1 + 1]; // 2 bytes unsigned char tel[1 + 1]; // 2 bytes unsigned char note[1 + 1]; // 2 bytes } T_PAT_INFO; int main() { printf("Size of T_PAT_INFO: %zu bytes\n", sizeof(T_PAT_INFO)); // 打印关键类型大小供参考 printf("Size of unsigned long: %zu bytes\n", sizeof(unsigned long)); printf("Size of enum (E_SEX): %zu bytes\n", sizeof(E_SEX)); return 0; } ``` ##### 代码解释: 1. **枚举定义**:`E_SEX`、`E_BLOOD_TYPE`、`E_PAT_TYPE` 被定义为简单枚举(如 `MALE`/`FEMALE`),确保编译器配空间(通常 4 字节)。 2. **结构体定义**:`T_PAT_INFO` 严格按用户声明定义,包括数组大小(如 `surName[21]`)。 3. **`main` 函数**: - `sizeof(T_PAT_INFO)` 返回结构体总大小(包括任何编译器填充)。 - 额外打印 `unsigned long` 和枚举大小,帮助验证系统假设。 4. **编译与运行**: - 在 Linux 或 Windows 上使用 GCC 编译:`gcc -o struct_size struct_size.c`,然后运行 `./struct_size`。 - 输出示例: - 32 位系统:`Size of T_PAT_INFO: 148 bytes` - 64 位 Linux:`Size of T_PAT_INFO: 160 bytes` ##### 注意事项: - 实际大小可能因编译器优化(如 `#pragma pack`)或系统而异。例如,在 Windows x64 上 `unsigned long` 为 4 字节,大小可能接近 148 字节。 - 要减少大小,可调整成员顺序(如将小类型如 `bPace` 与 `char` 数组相邻),或使用编译器指令(如 `#pragma pack(1)` 禁用填充),但可能影响性能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码不停Ti

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值