跨平台VM的C内存管理

发布于 2024-08-08 14:08:42 字数 5244 浏览 5 评论 0原文

我问了一个关于我得到的 C 型尺寸的 问题一个很好的答案,但我意识到我可能无法很好地表达这个问题以达到我的目的。

在转为软件工程师之前,我的背景是计算机工程师,所以我喜欢计算机架构,并且一直在考虑制作虚拟机。我刚刚完成了一个有趣的项目,在 Java 上制作 VM,对此我感到非常自豪。但存在一些法律问题,我现在无法开源它,而且我目前有一些空闲时间。所以我想看看我是否可以在 C 上制作另一个虚拟机(速度更快),只是为了娱乐和教育。

问题是我不是 C 程序,上次我写一个非琐碎的 C 问题已经是十多年前了。我曾经是 Pascal、Delphi,现在是 Java 和 PHP 程序员。

我可以预见到许多障碍,我正在尝试解决一个障碍,那就是访问现有的库(在 Java 中,反射解决了这个问题)。

我计划通过数据缓冲区(类似于堆栈)来解决这个问题。我的虚拟机的客户端可以编程将数据放入这些堆栈中,然后再给我指向本机函数的指针。

int main(void) {
    // Prepare stack
    int   aStackSize = 1024*4;
    char *aStackData = malloc(aStackSize);

    // Initialise stack
    VMStack aStack;
    VMStack_Initialize(&aStack, (char *)aStackData, aStackSize);

    // Push in the parameters
    char *Params = VMStack_CurrentPointer(&aStack);
    VMStack_Push_int   (&aStack, 10  ); // Push an int
    VMStack_Push_double(&aStack, 15.3); // Push a double

    // Prepare space for the expected return
    char *Result = VMStack_CurrentPointer(&aStack);
    VMStack_Push_double(&aStack, 0.0); // Push an empty double for result

    // Execute
    void (*NativeFunction)(char*, char*) = &Plus;
    NativeFunction(Params, Result); // Call the function

    // Show the result
    double ResultValue = VMStack_Pull_double(&aStack); // Get the result
    printf("Result:  %5.2f\n", ResultValue);               // Print the result

    // Remove the previous parameters
    VMStack_Pull_double(&aStack); // Pull to clear space of the parameter
    VMStack_Pull_int   (&aStack); // Pull to clear space of the parameter

    // Just to be sure, print out the pointer and see if it is `0`
    printf("Pointer: %d\n", aStack.Pointer);

    free(aStackData);
    return EXIT_SUCCESS;
}

原生函数的push、pull和调用可以通过字节码触发(这就是后面VM的制作方式)。

为了完整起见(以便您可以在自己的机器上尝试),这里是 Stack 的代码:

typedef struct {
    int  Pointer;
    int  Size;
    char *Data;
} VMStack;

inline void   VMStack_Initialize(VMStack *pStack, char *pData, int pSize) __attribute__((always_inline));
inline char   *VMStack_CurrentPointer(VMStack *pStack)                    __attribute__((always_inline));
inline void   VMStack_Push_int(VMStack *pStack, int pData)                __attribute__((always_inline));
inline void   VMStack_Push_double(VMStack *pStack, double pData)          __attribute__((always_inline));
inline int    VMStack_Pull_int(VMStack *pStack)                           __attribute__((always_inline));
inline double VMStack_Pull_double(VMStack *pStack)                        __attribute__((always_inline));

inline void VMStack_Initialize(VMStack *pStack, char *pData, int pSize) {
    pStack->Pointer = 0;
    pStack->Data    = pData;
    pStack->Size    = pSize;
}

inline char *VMStack_CurrentPointer(VMStack *pStack) {
    return (char *)(pStack->Pointer + pStack->Data);
}

inline void VMStack_Push_int(VMStack *pStack, int pData) {
    *(int *)(pStack->Data + pStack->Pointer) = pData;
    pStack->Pointer += sizeof pData; // Should check the overflow
}
inline void VMStack_Push_double(VMStack *pStack, double pData) {
    *(double *)(pStack->Data + pStack->Pointer) = pData;
    pStack->Pointer += sizeof pData; // Should check the overflow
}

inline int VMStack_Pull_int(VMStack *pStack) {
    pStack->Pointer -= sizeof(int);// Should check the underflow
    return *((int *)(pStack->Data + pStack->Pointer));
}
inline double VMStack_Pull_double(VMStack *pStack) {
    pStack->Pointer -= sizeof(double);// Should check the underflow
    return *((double *)(pStack->Data + pStack->Pointer));
}

在本机函数方面,我创建了以下代码用于测试目的:

// These two structures are there so that Plus will not need to access its parameter using
//    arithmetic-pointer operation (to reduce mistake and hopefully for better speed).
typedef struct {
    int    A;
    double B;
} Data;
typedef struct {
    double D;
} DDouble;

// 这是一个用于显示的辅助函数 void PrintData(数据 *pData, DDouble *pResult) { printf("%5.2f + %5.2f = %5.2f\n", pData->A*1.0, pData->B, pResult->D); }

// 一些本机函数 void Plus(char* pParams, char* pResult) { 数据*D = (数据*)pParams; // 无需算术指针操作即可访问数据 DDouble *DD = (DDouble *)pResult; // 返回也一样 DD->D = D->A + D->B; 打印数据(D,DD); }

执行时,上面的代码返回:

10.00 + 15.30 = 25.30
Result:  25.30
Pointer: 0

This work well on my machine (Linux x86 32bits GCC-C99)。如果这也适用于其他操作系统/架构,那就太好了。但我们至少必须注意三个与内存相关的问题。

1)。数据大小 - 似乎如果我在同一架构上使用相同的编译器编译虚拟机和本机函数,则大小类型应该相同。

2)。字节顺序 - 与数据大小相同。

3)。内存对齐 - 这是问题,因为填充字节可能会添加到结构中,但在准备参数堆栈时很难同步它(除了硬编码之外,没有办法知道如何添加填充)。

我的问题是:

1)。如果我知道类型的大小,有没有办法修改推和拉函数以与结构填充完全同步? (修改为让编译器像 Datasize 和 Endians 问题一样处理它)。

2)。如果我将结构打包为 1(使用 #pragma pack(1)); (2.1) 性能损失可以接受吗? (2.2) 程序稳定性是否会受到威胁?

3)。填充 2、4 或 8 怎么样?对于一般的 32 位系统或 64 位系统来说,哪个应该更好?

4).你能指导我找到一个精确填充算法的文档,比如 x86 上的 GCC 吗?

5)。有更好的办法吗?

注意:跨平台这不是我的最终目标,但我无法抗拒。另外,性能不是我的目标,只要它不是那么难看。所有这些都是为了娱乐和学习。

抱歉我的英语和很长的帖子。

预先感谢大家。

I asked a question about C-type sizes which I get a pretty good answer but I realized that I may not formulate the question very well to be useful for my purpose.

My background was from Computer Engineer before moves to Software Engineer so I like computer architectures and always thinking about making VM. I've just finished an interesting project making VM on Java which I am quite proud with. But there is some legal problems I can't open-source it now and I am currently have some free time. So I want to see if I can make another VM on C (with better speed) just for fun and educational.

The thing is I am not a C program the last time I wrote a non-trivia C problem was more than 10 years ago. I was Pascal, Delphi, and now Java and PHP programmer.

There are number of obstacles I can foresee and I am trying to tackle one and that is accessing existing library (in Java, reflection solves this problem).

I plan to solve this by having a buffer of data (similar to stack). The client of my VM can program to put data into these stack before giving me to pointer to native function.

int main(void) {
    // Prepare stack
    int   aStackSize = 1024*4;
    char *aStackData = malloc(aStackSize);

    // Initialise stack
    VMStack aStack;
    VMStack_Initialize(&aStack, (char *)aStackData, aStackSize);

    // Push in the parameters
    char *Params = VMStack_CurrentPointer(&aStack);
    VMStack_Push_int   (&aStack, 10  ); // Push an int
    VMStack_Push_double(&aStack, 15.3); // Push a double

    // Prepare space for the expected return
    char *Result = VMStack_CurrentPointer(&aStack);
    VMStack_Push_double(&aStack, 0.0); // Push an empty double for result

    // Execute
    void (*NativeFunction)(char*, char*) = &Plus;
    NativeFunction(Params, Result); // Call the function

    // Show the result
    double ResultValue = VMStack_Pull_double(&aStack); // Get the result
    printf("Result:  %5.2f\n", ResultValue);               // Print the result

    // Remove the previous parameters
    VMStack_Pull_double(&aStack); // Pull to clear space of the parameter
    VMStack_Pull_int   (&aStack); // Pull to clear space of the parameter

    // Just to be sure, print out the pointer and see if it is `0`
    printf("Pointer: %d\n", aStack.Pointer);

    free(aStackData);
    return EXIT_SUCCESS;
}

The push, pull and invocation of native function can be triggered by a byte code (that is how VM will later be made).

For the sake of completeness (so that you can try it on you machine), here is the code for Stack:

typedef struct {
    int  Pointer;
    int  Size;
    char *Data;
} VMStack;

inline void   VMStack_Initialize(VMStack *pStack, char *pData, int pSize) __attribute__((always_inline));
inline char   *VMStack_CurrentPointer(VMStack *pStack)                    __attribute__((always_inline));
inline void   VMStack_Push_int(VMStack *pStack, int pData)                __attribute__((always_inline));
inline void   VMStack_Push_double(VMStack *pStack, double pData)          __attribute__((always_inline));
inline int    VMStack_Pull_int(VMStack *pStack)                           __attribute__((always_inline));
inline double VMStack_Pull_double(VMStack *pStack)                        __attribute__((always_inline));

inline void VMStack_Initialize(VMStack *pStack, char *pData, int pSize) {
    pStack->Pointer = 0;
    pStack->Data    = pData;
    pStack->Size    = pSize;
}

inline char *VMStack_CurrentPointer(VMStack *pStack) {
    return (char *)(pStack->Pointer + pStack->Data);
}

inline void VMStack_Push_int(VMStack *pStack, int pData) {
    *(int *)(pStack->Data + pStack->Pointer) = pData;
    pStack->Pointer += sizeof pData; // Should check the overflow
}
inline void VMStack_Push_double(VMStack *pStack, double pData) {
    *(double *)(pStack->Data + pStack->Pointer) = pData;
    pStack->Pointer += sizeof pData; // Should check the overflow
}

inline int VMStack_Pull_int(VMStack *pStack) {
    pStack->Pointer -= sizeof(int);// Should check the underflow
    return *((int *)(pStack->Data + pStack->Pointer));
}
inline double VMStack_Pull_double(VMStack *pStack) {
    pStack->Pointer -= sizeof(double);// Should check the underflow
    return *((double *)(pStack->Data + pStack->Pointer));
}

On the native function side, I created the following for testing purpose:

// These two structures are there so that Plus will not need to access its parameter using
//    arithmetic-pointer operation (to reduce mistake and hopefully for better speed).
typedef struct {
    int    A;
    double B;
} Data;
typedef struct {
    double D;
} DDouble;

// Here is a helper function for displaying void PrintData(Data *pData, DDouble *pResult) { printf("%5.2f + %5.2f = %5.2f\n", pData->A*1.0, pData->B, pResult->D); }

// Some native function void Plus(char* pParams, char* pResult) { Data *D = (Data *)pParams; // Access data without arithmetic-pointer operation DDouble *DD = (DDouble *)pResult; // Same for return DD->D = D->A + D->B; PrintData(D, DD); }

When executed, the above code returns:

10.00 + 15.30 = 25.30
Result:  25.30
Pointer: 0

This work well on my machine (Linux x86 32bits GCC-C99). It will be very nice if this works on other OS/Architecture too. But there are AT LEAST three memory-related issures we have to be aware of.

1). Data size - It seems like if I compile both VM and native functions using the same compiler on the same architecture, the size types should be the same.

2). Endianness - Same with Data size.

3). Memory alignment - Which is the problem as padding-bytes may be added in struct but it is hard to synchronize it when prepare parameter stack as (there is no way to know how padding is added except for hard coding).

My questions are:

1). If I know the size of the types, is there a way to modify push and pull function to exactly synchronize with struct padding? (modify to let compiler takes care of it like Datasize and Endians problems).

2). If I pack structure by one (using #pragma pack(1)); (2.1) Will the performance penalty be acceptable? and (2.2) Will the program stability be at risk?

3). How about padding by 2,4, or 8? Which should be good for general 32 or 64 bits system?

4). Can you guide me to a documentation for an exact padding algorithm let say for GCC on x86?

5). Is there is a better way?

NOTE: Cross-platform it is not my ultimate goal but I can't resist. Also, performance is not my target as soon as it is not so ugly. All these are for fun and learning.

Sorry for my English and the very long post.

Thanks everyone in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

困倦 2024-08-15 14:08:42

切线评论

这些第一项与您提出的问题无关,但是...

// Execute
void (*NativeFunction)(char*, char*) = &Plus;
NativeFunction(Params, Result); // Call the function

我认为您可能应该在这里使用“void *”而不是“char *”。我还会有一个函数指针类型的 typedef:

typedef void (*Operator)(void *params, void *result);

然后你可以写:

Operator NativeFunction = Plus;

实际的函数也会被修改 - 但只是非常轻微:

void Plus(void *pParams, void *pResult)

另外,你有一个小命名问题 - 这个函数是 'IntPlusDoubleGivesDouble()',而不是通用“添加任意两种类型”功能。


直接回答问题

1).如果我知道类型的大小,有没有办法修改推和拉函数以与结构填充完全同步? (修改为让编译器像 Datasize 和 Endians 问题一样处理它)。

没有一个简单的方法可以做到这一点。例如,请考虑:

struct Type1
{
     unsigned char byte;
     int           number;
};
struct Type2
{
     unsigned char byte;
     double        number;
};

在某些体系结构(例如 32 位或 64 位 SPARC)上,Type1 结构将在 4 字节边界上对齐“number”,但 Type2 结构将在 4 字节边界上对齐“number”。 8 字节边界(并且可能在 16 字节边界上有一个“long double”)。您的“推送单个元素”策略会在推送“字节”值后将堆栈指针增加 1 - 因此,如果堆栈指针尚未正确,您可能希望在推送“数字”之前将堆栈指针移动 3 或 7对齐。 VM 描述的一部分将是任何给定类型所需的对齐;相应的推送代码在推送之前需要确保正确对齐。

2).如果我将结构打包一(使用#pragma pack(1)); (2.1) 性能损失可以接受吗? (2.2) 程序稳定性会受到威胁吗?

在 x86 和 x86_64 机器上,如果打包数据,则会因未对齐的数据访问而导致性能损失。在 SPARC 或 PowerPC(根据 mecki)等计算机上,您将收到总线错误或相反,类似的东西 - 您必须以正确的对齐方式访问数据。您可能会节省一些内存空间 - 但代价是性能。您最好以空间边际成本确保性能(这里包括“正确执行而不是崩溃”)。

3).填充 2、4 或 8 怎么样?对于一般的 32 位或 64 位系统来说,哪一个应该比较好?

在 SPARC 上,您需要将 N 字节基本类型填充到 N 字节边界。在 x86 上,如果您这样做,您将获得最佳性能。

4).您能否指导我查看精确填充算法的文档(例如 x86 上的 GCC)?

您必须阅读手册

5).有更好的办法吗?

请注意,带有单个字符后跟类型的“Type1”技巧为您提供了对齐要求 - 可能使用 中的“offsetof()”宏:

offsetof(struct Type1, number)

嗯,我不会将数据打包到堆栈上 - 我将使用本机对齐,因为这设置为提供最佳性能。编译器编写者不会随意向结构添加填充;他们把它放在那里是因为它对架构来说“最好”。如果您认为自己了解得更多,则可以预见通常的后果 - 速度较慢的程序有时会失败并且不那么可移植。

我也不相信我会在运算符函数中编写代码来假设堆栈包含结构。我会通过 Params 参数从堆栈中取出值,知道正确的偏移量和类型是什么。如果我推入一个整数和一个双精度数,那么我会拉出一个整数和一个双精度数(或者,也许以相反的顺序 - 我会拉出一个双精度数和一个整数)。除非您正在计划一个不寻常的虚拟机,否则很少有函数会有很多参数。

Tangential Comments

These first items are tangential to the questions you asked, but...

// Execute
void (*NativeFunction)(char*, char*) = &Plus;
NativeFunction(Params, Result); // Call the function

I think you should probably be using 'void *' instead of 'char *' here. I would also have a typedef for the function pointer type:

typedef void (*Operator)(void *params, void *result);

Then you can write:

Operator NativeFunction = Plus;

The actual function would be modified too - but only very slightly:

void Plus(void *pParams, void *pResult)

Also, you have a minor naming problem - this function is 'IntPlusDoubleGivesDouble()', rather than a general purpose 'add any two types' function.


Direct answers to the questions

1). If I know the size of the types, is there a way to modify push and pull function to exactly synchronize with struct padding? (modify to let compiler takes care of it like Datasize and Endians problems).

There isn't an easy way to do that. For example, consider:

struct Type1
{
     unsigned char byte;
     int           number;
};
struct Type2
{
     unsigned char byte;
     double        number;
};

On some architectures (32-bit or 64-bit SPARC, for example), the Type1 structure will have 'number' aligned at a 4-byte boundary, but the Type2 structure will have 'number' aligned on an 8-byte boundary (and might have a 'long double' on a 16-byte boundary). Your 'push individual elements' strategy would bump the stack pointer by 1 after pushing the 'byte' value - so you would want to move the stack pointer by 3 or 7 before pushing the 'number', if the stack pointer is not already appropriately aligned. Part of your VM description will be the required alignments for any given type; the corresponding push code will need to ensure the correct alignment before pushing.

2). If I pack structure by one (using #pragma pack(1)); (2.1) Will the performance penalty be acceptable? and (2.2) Will the program stability be at risk?

On x86 and x86_64 machines, if you pack the data, you will incur a performance penalty for the misaligned data access. On machines such as SPARC or PowerPC(per mecki), you will get a bus error or something similar instead - you must access the data at its proper alignment. You might save some memory space - at a cost in performance. You'd do better to ensure performance (which here includes 'performing correctly instead of crashing') at the marginal cost in space.

3). How about padding by 2,4, or 8? Which should be good for general 32 or 64 bits system?

On SPARC, you need to pad an N-byte basic type to an N-byte boundary. On x86, you will get best performance if you do the same.

4). Can you guide me to a documentation for an exact padding algorithm let's say for GCC on x86?

You would have to read the manual.

5). Is there is a better way?

Note that the 'Type1' trick with a single character followed by a type gives you the alignment requirement - possibly using the 'offsetof()' macro from <stddef.h>:

offsetof(struct Type1, number)

Well, I would not pack the data on the stack - I would work with the native alignment because that is set to give the best performance. The compiler writer does not idly add padding to a structure; they put it there because it works 'best' for the architecture. If you decide you know better, you can expect the usual consequences - slower programs that sometimes fail and are not as portable.

I am also not convinced that I would write the code in the operator functions to assume that the stack contained a structure. I would pull the values off the stack via the Params argument, knowing what the correct offsets and types were. If I pushed an integer and a double, then I'd pull an integer and a double (or, maybe, in reverse order - I'd pull a double and an int). Unless you are planning an unusual VM, few functions will have many arguments.

青巷忧颜 2024-08-15 14:08:42

有趣的帖子,表明您付出了很多努力。几乎是理想的SO职位。

我没有现成的答案,所以请耐心等待。我还得问几个问题:P

1).如果我知道类型的大小,有没有办法修改推和拉函数以与结构填充完全同步? (修改为让编译器像 Datasize 和 Endians 问题一样处理它)。

这仅仅是从性能角度来看吗?您是否计划将指针与本机算术类型一起引入?

2).如果我将结构打包一(使用#pragma pack(1)); (2.1) 性能损失可以接受吗? (2.2) 程序稳定性会受到威胁吗?

这是一个实现定义的东西。不是您可以跨平台依赖的东西。

3).填充 2、4 或 8 怎么样?对于一般的 32 位或 64 位系统来说,哪一个应该比较好?

与本机字大小匹配的值应该可以为您提供最佳性能。

4).您能否指导我查看精确填充算法的文档(例如 x86 上的 GCC)?

我不知道我的头顶有什么。但我看到过类似于 this 的代码。

请注意,您可以 指定使用 GCC 的变量(它还有一个名为 default_struct __attribute__((packed)) 的东西,可以关闭填充)。

Interesting post and shows that you've put in a lot of work. Almost the ideal SO post.

I do not have ready answers, so please bear with me. I will have to ask a few more questions :P

1). If I know the size of the types, is there a way to modify push and pull function to exactly synchronize with struct padding? (modify to let compiler takes care of it like Datasize and Endians problems).

Is this from a performance point of view only? Are you planning to introduce pointers along with native arithmetic types?

2). If I pack structure by one (using #pragma pack(1)); (2.1) Will the performance penalty be acceptable? and (2.2) Will the program stability be at risk?

This is an implementation-defined thing. Not something you can count on across platforms.

3). How about padding by 2,4, or 8? Which should be good for general 32 or 64 bits system?

The value that matches with the native word size ought to give you optimal performance.

4). Can you guide me to a documentation for an exact padding algorithm let say for GCC on x86?

I don't know of any of the top of my head. But I have seen code similar to this being used.

Note, that you can specify attributes of variables using GCC (which also has something called default_struct __attribute__((packed)) that turns off padding).

南…巷孤猫 2024-08-15 14:08:42

这里有一些非常好的问题,其中许多会纠结于一些重要的设计问题,但对于我们大多数人来说 - 我们可以看到您正在努力的方向(在我写这篇文章时刚刚发布,以便您可以看到您正在产生兴趣)我们可以很好地理解你的英语,你正在努力解决一些编译器问题和一些语言设计问题 - 解决这个问题变得很困难,但因为你已经在 J​​NI 中工作,所以有希望......

一方面,我会尝试摆脱实用程序;许多人,非常多会不同意这一点。有关原因的规范讨论请参阅 D 语言在该问题上的立场的理由。另一方面,您的代码中隐藏着一个 16 位指针。

这些问题几乎无穷无尽,经过深入研究,很可能让我们陷入反对和内部顽固之中。如果我可以建议阅读 Kenneth Louden 的主页 以及英特尔架构手册。我有,我试着读过。数据结构对齐以及您提出讨论的许多其他问题都深深地埋藏在历史编译器科学中,并且可能会让您沉浸在谁知道什么的问题中。 (用于不可预见的后果的俚语或惯用语)

话虽如此,这里是:

  1. C 型尺寸
    什么类型尺寸?
  2. 搬到之前的计算机工程师
    软件工程师
    学过微控制器吗?欣赏一下唐·兰卡斯特的一些作品。
  3. Pascal、Delphi,以及现在的 Java 和 PHP
    程序员。

    尽管很多人会展示或尝试展示如何使用它们来编写强大的基本例程,但它们相对而言已从处理器的基本基础架构中移除。我建议查看 David Eck 的递归下降解析器,以了解如何开始研究这个问题。此外,Kenneth Louden 还实现了“Tiny”,它是一个实际的编译器。不久前我发现了一些东西,我认为它被称为 asm dot org ...非常先进、非常强大的工作可供研究,但开始用汇编程序编写并打算进入编译器科学是一个漫长的过程。此外,大多数架构在处理器与处理器之间存在不一致的差异。
  4. 访问现有库

周围有很多库,Java 有一些不错的库。我不知道其他人的情况。一种方法是尝试编写一个库。 Java 拥有良好的基础,并为人们尝试想出更好的东西留下了空间。从改进 Knuth-Morris-Pratt 法或其他方法开始:不乏可以开始的地方。尝试计算机编程算法目录,当然,看看NIST 的算法和数据结构词典

  1. always_inline

不一定,请参阅 Dov Bulka - 工人持有计算机科学博士学位,也是时间效率/可靠性-鲁棒性等领域的熟练作者,这些领域不受某些“商业模式”范式的影响,从中我们得到了一些“哦!这并不重要”在真正重要的问题上。

作为结束语,正如您所描述的,仪表和控制占成熟编程技能实际市场的 60% 以上。出于某种原因,我们听到的最多的是商业模式。让我与您分享我从可靠来源获得的内幕消息。 10% 到 60% 或更多实际的安全和财产风险来自车辆问题,而不是来自防盗、盗窃等。您永远不会听到“90 天在县矿物开采设施中破坏矿物!”的呼吁。对于交通罚单,事实上大多数人甚至没有意识到交通罚单属于(北美 - 美国)第 4 类轻罪,并且实际上可以归类为此类行为。

在我看来,你已经朝着一些好的工作迈出了一大步,......

There are some very good questions here, many of them will get tangled in some important design issues but for most of us - we can see what you are working towards ( dirkgently just posted as I write so you can see you are generating interest ) we can understand your English well enough that what you are working towards is some compiler issues and some language design issues - it becomes difficult to work the question but in that you are already working in JNI there is hope ...

For one thing, I would try to get away from pragmas; Many folks, very many will disagree with that. For canonical discussion of why see the justification for the D language position on the issue. For another, there is a 16-bit pointer buried in your code.

The issues are near endless, well studied, and likely to get us buried in opposition and intramural intransigence. if I may suggest reading Kenneth Louden's Home Page as well as The intel architecture manual. I have it, I have tried to read it. Data structure alignment, along with many of the other issues you put up for discussion are deeply buried in historical compiler science and are likely to get you awash in who knows what. ( slang or idiomatic for unforeseeable matters of consequence )

With that said, here goes:

  1. C-type sizes
    What type sizes?
  2. Computer Engineer before moves to
    Software Engineer

    Ever studied microcontrollers? Hava a look at some of Don Lancaster's work.
  3. Pascal, Delphi, and now Java and PHP
    programmer.

    Those are comparatively removed from the base fundamental architecture of processors, though plenty of persons will show or try to show how they can be used to write powerful and fundamental routines. I suggest looking at David Eck's recursive descent parser to see exactly how to begin study of the matter. As well, Kenneth Louden has an implementation of "Tiny" which is an actual compiler. I found something not too long ago that I think was called asm dot org ... very advanced, very powerful work was available for study there but it is a long haul to start writing in assembler intending to get into compiler science. Additionally, most architectures have differences that are not consistent from one processor to another.
  4. accessing existing library

There are many libs around, Java has some good ones. I don't know about the others. One approach is to try to write a lib. Java has a good base and leaves room for people like to to try to come up with something better. Start with improving Knuth-Morris-Pratt or something: There is just no shortage of places to start. Try Computer Programming Algorithms Directory and for sure, look at Dictionary of Algorithms and Data Structures at NIST

  1. always_inline

Not necessarily, see Dov Bulka - the worker holds a Doctorate in CS and as well is a proficient author in areas where time-efficiency / reliability-robustness and so on are not subject to some of the "business model" paradigm wherefrom we get some of the "Oh! that doesn't matter" on issues that actually do matter.

As a closing note, instrumentation and control comprise over 60% of the actual market for accomplished programming skills as you describe. For some reason, we hear mostly about the business model. Let me share with you and inside tidbit I have from a reliable source. From 10% to 60% or more actual safety and property risk comes from vehicular issues than comes from burglar, theft and that sort of thing. You will never hear appeals for "90 days bustin minerals at the county mineral extraction faciltiy!" for traffic tickets, in fact most people do not even realize traffic citations are ( N.A. - U.S.A. ) class 4 misdemeanor and are actually classifiable as such.

Sounds to me like you have taken a good step towards some good work, ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文