有时用一个使用大块静态内存的小程序来模拟一些东西很方便.我注意到在改用Fedora 15之后程序需要很长时间才能编译.我们说30秒对0.1秒.更奇怪的是ld(链接器)正在最大化CPU并慢慢开始吃掉所有可用的内存.经过一番摆弄后,我设法找到了这个新问题与我的交换文件大小之间的关联.以下是用于本讨论的示例程序:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (200*M)
size_t g_arr[GIANT_SIZE];
int main( int argc, char **argv){
int i;
for(i = 0; i<10; i++){
printf("This should be zero: %d\n",g_arr[i]);
}
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
该程序有一个巨大的数组,其声明大小约为200*8MB = 1.6GB的静态内存.编译此程序需要花费大量时间:
[me@bleh]$ time gcc HugeTest.c
real 0m12.954s
user 0m6.995s
sys 0m3.890s
[me@bleh]$
Run Code Online (Sandbox Code Playgroud)
13s对于~13行C程序!?那是不对的.键号是静态存储空间的大小.一旦它大于总交换空间,它就会再次开始快速编译.例如,我有5.3GB的交换空间,因此将GIANT_SIZE更改为(1000*M)会给出以下时间:
[me@bleh]$ time gcc HugeTest.c
real 0m0.087s
user 0m0.026s
sys 0m0.027s
Run Code Online (Sandbox Code Playgroud)
啊,那更像是它!为了进一步说服自己(和你自己,如果你在家里尝试这个)交换空间确实是神奇的数字,我尝试将可用的交换空间更改为真正庞大的19GB,并尝试再次编译(1000*M)版本:
[me@bleh]$ ls -ali /extraswap
5986 -rw-r--r-- 1 root root 14680064000 Jul 26 15:01 /extraswap
[me@bleh]$ …Run Code Online (Sandbox Code Playgroud) 今天,我在尝试使用位字段时发现了令人担忧的行为.为了便于讨论和简化,这是一个示例程序:
#include <stdio.h>
struct Node
{
int a:16 __attribute__ ((packed));
int b:16 __attribute__ ((packed));
unsigned int c:27 __attribute__ ((packed));
unsigned int d:3 __attribute__ ((packed));
unsigned int e:2 __attribute__ ((packed));
};
int main (int argc, char *argv[])
{
Node n;
n.a = 12345;
n.b = -23456;
n.c = 0x7ffffff;
n.d = 0x7;
n.e = 0x3;
printf("3-bit field cast to int: %d\n",(int)n.d);
n.d++;
printf("3-bit field cast to int: %d\n",(int)n.d);
}
Run Code Online (Sandbox Code Playgroud)
该程序故意导致3位位域溢出.这是使用"g ++ -O0"编译时的(正确)输出:
3位字段转换为int:7
3位字段转换为int:0
这是使用"g ++ -O2"(和-O3)编译时的输出:
3位字段转换为int:7
3位字段转换为int:8
检查后一个例子的程序集,我发现了这个:
movl …Run Code Online (Sandbox Code Playgroud) C语言的位域提供了一种在结构中定义任意宽度字段的相当方便的方法(永远不要在一分钟内解决可移植性问题.)例如,这是一个带有几个字段和'flag'的简单结构:
#pragma pack(push,1)
struct my_chunk{
unsigned short fieldA: 16;
unsigned short fieldB: 15;
unsigned short fieldC: 1;
};
#pragma pop()
Run Code Online (Sandbox Code Playgroud)
添加#pragma语句将此结构打包成一个32位字(确保指针的指针操作my_chunk对齐,例如,节省空间).
访问每个字段在语法上非常好:
struct my_chunk aChunk;
aChunk.fieldA = 3;
aChunk.fieldB = 2;
aChunk.fieldC = 1;
Run Code Online (Sandbox Code Playgroud)
在没有语言帮助的情况下执行此操作的替代方法相当丑陋,并且几乎可以转换为汇编程序.例如,一种解决方案是为要访问的每个字段设置bitshift宏:
#define FIELD_A 0xFF00
#define FIELD_B 0x00FE
#define FIELD_C 0x0001
#define get_field(p, f) ((*p)&f)
#define set_field(p, f, v) (*p) = (v<<f) + (*p)&(~f)
...
set_field(&my_chunk, FIELD_A, 12345);
Run Code Online (Sandbox Code Playgroud)
..或类似的东西(为了更正式,看看这个)
所以问题是,如果我想在go中"做"bitfields,这样做的最佳做法是什么?
为了澄清我的问题,让我们从一个示例程序开始:
#include <stdio.h>
#pragma pack(push,1)
struct cc {
unsigned int a : 3;
unsigned int b : 16;
unsigned int c : 1;
unsigned int d : 1;
unsigned int e : 1;
unsigned int f : 1;
unsigned int g : 1;
unsigned int h : 1;
unsigned int i : 6;
unsigned int j : 6;
unsigned int k : 4;
unsigned int l : 15;
};
#pragma pack(pop)
struct cc c;
int main(int argc, char **argv)
{ …Run Code Online (Sandbox Code Playgroud) bit-fields ×3
c ×2
c++ ×2
gcc ×2
bit-packing ×1
go ×1
ld ×1
linux ×1
optimization ×1
swap ×1
visual-c++ ×1