0

I might not have had a counterexample when I got the reply "A pointer is just an address, what's the difficulty?" but I didn't really buy such a simple explanation and at assembly code it's not obvious what's a pointer for 2 different C programs that generate the same assembly.

 cat pelle.s valle.s 
    .file   "pelle.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    $0, %eax
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits
    .file   "valle.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    $0, %eax
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits

1) An address to a variable is &var1 and the pointer is int* var1 written differently than the address. 2) When I compile 2 C programs where the only difference is pointing then there is no difference in the assembly:

$ diff pelle.c valle.c ;cat pelle.c valle.c;diff pelle.s valle.s 
3c3
< int * pelle;
---
>  int valle;
#include <stdio.h>
int main(void) {
int * pelle;
    return 0;
}
#include <stdio.h>
int main(void) {
 int valle;
    return 0;
}
1c1
<   .file   "pelle.c"
---
>   .file   "valle.c"

But what conclusions can be drawn from no difference in generated assembly to investigate the "simple and obvious difference" between a pointer declaration and other type? Is the simplistic answer right all along, a pointer is just a variable and there's no point in more analysis? Or that the difference between a pointer and a variable is a case of "sugar" since the types are removed at assembly level where there is no difference? Will a difference in the generated assembly show a diff if I use pointers as arguments to a function and there will indeed be a difference for some pointer usage and this example is too trivial and can't be generalized? So when types are removed in the generated assembly, can I conclude that type difference indeed will result in a difference i nthe generated assembly for a non-trivial example e.g. pointers as arguments and this example is not very good since it looks like the generated assembly disregards typing, while type difference such as this will make a difference in generated assembly for another example?

int valle;
int * pelle;

 Assembler

.data
.align 2
.global valle
valle: .word 0

.data
.align 2
.global pelle
pelle: .word 0

5 Answers 5

5

They produce the same assembly because the compiler removes the unused variable. It does not contribute to the code, so it does not show up in the assembly. You may be able to see a difference if you turn off all optimizations.

But let's look at the assembly after removing all cruft (added line numbers for making the explanation simpler):

1: main:
2:    pushl   %ebp
3:    movl    %esp, %ebp
4:    movl    $0, %eax
5:    popl    %ebp
6:    ret

What this essentially does is to set up the stack frame for a new function (line 2 and 3), set the return value to 0 (line 4) and restore the stack frame and return from the function (lines 5 and 6).

This translates to the following C code:

int main(void)
{
    return 0;
}

Which is exactly what the compiler sees after removing the variable that is not being used.

So in short, the conclusion is that the assembly is the same because the programs are the same. The fact that you declare a local variable that does not contribute to the program does not make it a different program.

2

The only absolute conclusion you can draw is that the two programs will behave the same if they have been compiled with the same compiler for the same target platform.

If you then analyse the differences in the source code, you may also be able to deduce that there are semantic similarities / equivalences.

In fact, it is highly likely that there will be semantic equivalences at the source code level ... though they may depend on non-portable assumptions in the code; e.g. that an int and an int* have the same size.

1

The fact that two programs compile to the same assembly code means that the two programs produce the same behavior. Differences in programs that don't contribute to the behavior (such as the unused variables in your examples) may or may not show up in the assembly code. The compiler is fully within its rights to throw those parts out completely.


Assembly languages are untyped, which means that the concept of types doesn't exist in assembly. The concept of a type is a higher-level concept that limits what you can do with a variable.

In assembly language, a variable is nothing more than a piece of memory or a register that has been set aside for a particular purpose (where that purpose is determined by the programmer). The assembler will allow you to perform any known operation on a variable and it is your responsibility to ensure that the operation makes sense.

In higher-level languages that have the concept of types, you inform the compiler how you intend to use a variable ("I intend to use valle as a location for numbers and pelle as a location for addresses of integer variables") and the compiler takes on part of the burden to ensure that the operations you do with a variable make sense.

When compiling a higher-level language, the compiler checks that the type rules are obeyed by the program, but it throws the type information away after that because there is no way to keep it in assembly or machine language.
When reading assembly, the only way to derive type information is to look at how variables are being used in the generated assembly. And even then, the inferred type information may be incomplete.

0

If the two programs generate the same assembly, then you can be certain that if assembled using the same assembler, those will produce the same machine code. And that's about it.

But if that were the only point, then we'd all be coding in assembly. Programming languages are about abstractions. That's literally the whole point.

In C, pointers are part of that abstraction, but there's more than one way to achieve the same result. The result you achieve isn't how you measure the value of the abstraction, rather it's the baseline upon which the abstraction is constructed.

What matters is how a given language feature makes the code easier to reason through, easier to avoid mistakes, easier to communicate to others. And if that's not your goal, then you might as well write your code in assembly.

0

Your question is quite hard to follow, and I'm unsure which issue you want answered. My contribution is to point out that

  • at the assembly language level, there is absolutely no difference between a pointer and a value, and both can be stored in memory or loaded into a register
  • at the level of a C-like language a distinction is made between pointers and values so that the compiler can help you use them correctly
  • at the level of a higher level language there are no pointers, just values and references.

The main purpose of a higher level language and the compiler that supports it is to free you from thinking about machine level details. Pointers are such a detail, not part of the solution for any computing problem but merely part of the implementation detail of the program that executes the solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.