In C, we have data, and we have pointers. Pointers by themselves are binary data. So, at the hardware level there is no difference between data and pointers. Pointers must be an implementation. If we have a variable, that variable has two properties, the data and the address, which itself is a data, in a sense this creates an infinite pointer loop kind of thing. Since every pointer is a data, they must have a pointer that points to them, and the pointer that points to the pointer must have a pointer, and so on.
This type of implementation would only make sense if pointers are created on demand. Let's say we create a variable called a, does C immediately assign a pointer to this variable right after the variable being declared? Or is it when I explicitly try to pull the pointer by doing &a that C creates a pointer according to some internal algorithm?
in a sense this creates an infinite pointer loop kind of thing. Every pointer must have a parent pointer
This is logically incorrect. It's like saying: "A pointer is a street address. Every person has a street address. Therefore a street address is a pointer."
Pointers are variables containing addresses, but that doesn't make addresses pointers... something can have an address without a pointer used to access that address. Just like your machine code can contain integer values without them being stored in int variables.
Or is it when I explicitly try to pull the pointer by doing &a that C creates a pointer according to some internal algorithm?
Yes, kind of. Here the address is actually used by the program so the &a address must be stored somewhere. You can think of it as a temporary pointer variable if it helps. In practice, if we disassemble this code:
int a;
printf("%p\n", &a);
Then on gcc x86 this just results in a "load effective address" instruction. That is, the compiler stores the address in a register which is then passed on to printf as per that function's calling convention.
Your description is all wrong. It seems you are confusing C pointers and memory addresses at execution time. It's completely different things.
Pointers in C are no different from other data types. You get a pointer to type T only when you define one, i.e. like T* p; Just like you only get an int object when you define one (e.g. int a;).
At machine level it's completely different. In order to access objects (aka variables) stored in memory, the CPU needs a way to calculate the address of that object. The C standard does not care how it's done. It's an implementation detail that may differ from system to system.
Many implementations uses a "stack pointer" (stored in a CPU register) as reference for other variables. Instead of knowing the exact address of an object, the address is found as "value of stack pointer" plus an offset (i.e. SP+offset). This offset is then hardcoded into the execution binary, i.e. the instruction set of the CPU can have an instruction that do stuff like: "Read the memory at address SP+fixed_offset and store it in register X".
Take a look at this simple (and rather stupid) function:
unsigned long foo(unsigned long x)
{
unsigned long y = x;
putchar('a');
return y + x;
}
This defines two "unsigned long" objects and return their sum. Using godbolt.org, gcc 11.2, and flag -fomit-frame-pointer (no optimization to keep things simple), I get this machine code (with my comments added):
foo:
sub rsp, 40 // Change stack pointer to reserve 40 bytes
mov QWORD PTR [rsp+8], rdi // Save the passed value (i.e. register rdi)
// in object x at memory address rsp+8
mov rax, QWORD PTR [rsp+8] // Read object x into register rax
mov QWORD PTR [rsp+24], rax // Save rax in object y at memory address rsp+24
// So this is really y = x
mov edi, 97 // These are just
call putchar // putchar('a');
mov rdx, QWORD PTR [rsp+24] // Read object y into register rdx
mov rax, QWORD PTR [rsp+8] // Read object x into register rax
add rax, rdx // rax = rax + rdx, i.e. rax = y + x
add rsp, 40 // Restore stack pointer, i.e. release
// the 40 bytes
ret // Return. The returned value is in register rax
So on this specific system the memory address of x is found as "stack pointer + 8" and the memory address of y is found as "stack pointer + 24". From the machine code we can't tell the actual memory address of the variables as it depends on the value of the stack pointer (rsp) when the function is called.
The lesson is that - yes, at machine level there is a way to get the memory address of x and y but there is no such thing as an automatically created and stored pointer to any of them.
Now for fun - the same code compiled with -O2 gives:
foo:
push rbx
mov rsi, QWORD PTR stdout[rip]
mov rbx, rdi
mov edi, 97
call putc
lea rax, [rbx+rbx]
pop rbx
ret
Take a look at the code and see if you can find x and y ;-)
(but - to repeat - all this is not described by the C standard, it's just how it's done on this specific system).
BTW Also be aware that objects/variables define by the C code may exist only in CPU registers, i.e. the are never written to memory and consequently they don't even have an address.
Every variable is stored in the memory . The address (pointer) is not stored separately, it is simply the location of the variable.
(This is actually more complex than that: Some variables might normally stay in processor registers instead of RAM, but if you take their address, the compiler might store them in memory so that the address can be taken. Or if you just print the address, it might invent a fake address for them.)
If you take the address of a variable and store it in a pointer, you create a new variable, and assign the value of the address of the other variable. But the address of this new variable is not stored separately, it is simply the location of the variable.
There is no "infinite pointer loop", unless your code makes infinite number of variables and your computer has infinite memory.
What determines the address then? How does the program know where the variable is stored?
This is controlled by the operating system, which gives your program memory blocks based on the memory allocations you make. Your program determines (at compile time) which variable is in which address relative to this memory block.
I would not say "we have data, and we have pointers". Yes, pointers are different, but saying it this way doesn't really capture what's different about them.
Any variable has a location (also called an address), and a value (perhaps also called "contents"). If you say
int i = 5;
the value is 5, and we're not precisely sure where the location is (because we usually don't care), although the identifier i helps us keep track of it, whatever it is. But there are definitely two things, the location or address, and the contents or value.
If you say
int *ip = &i;
once again you have a variable named ip, and a value, which in this case is a pointer, or an address, and what it's the address of is the same as that other variable i. And then there's also a value in the pointed-to location. So you now have three things:
the variable ip, and
its value, which is "pointer to i", and
the pointed-to value, which is 5.
Almost nothing gets "created on demand". The variable i got created because you requested it. The variable ip got created because you requested it.
You can draw a picture like this to help you keep track of things:
+---------+
i: | 5 |
+---------+
^
|
+-------|-------+
ip:| * |
+---------------+
The only thing that happens automatically, behind your back, that you can't necessarily see, is the assignment of some actual, numeric addresses for your variables. You can see those if you print them out using %p:
printf("address of i: %p\n", &i);
printf("address of ip: %p\n", &ip);
and you will notice that ip holds i's address:
printf("value of ip: %p\n", ip);
or you can look at everything — i's two things, and ip's three things — like this:
printf("i: loc %p, value %d\n", &i, i);
printf("ip: loc %p, value %p, pointed-to value %d\n", &ip, ip, *ip);
To see what's going on a little more explicitly, let's write this as an actual program. For the moment, I'm going to have the variables i and ip be "global" variables, although this is unusual, because normally they'd be "local" variables, declared inside main. Also I'm going to declare a third variable j.
#include <stdio.h>
int i = 5;
int j = 66;
int *ip = &i;
int main()
{
printf(" i: loc %p, value %d\n", &i, i);
printf(" j: loc %p, value %d\n", &j, j);
printf("ip: loc %p, value %p, pointed-to value %d\n", &ip, ip, *ip);
}
the output I get is
i: loc 0x10837b018, value 5
j: loc 0x10837b01c, value 66
ip: loc 0x10837b020, value 0x10837b018, pointed-to value 5
You'd get different addresses on your computer, but basically a similar pattern.
If you're on a Unix-like system, you can run the nm command to see your program's "namelist", or symbol table, which is a list of all the identifiers in your program, and their addresses. When I run it on the program above, I get something like this:
$ nm a.out
000000010837b018 D _i
000000010837b01c D _j
000000010837b020 D _ip
0000000108370ec0 T _main
This shows me that my program has three things in the "data" segment, which are my variables, and one thing in the "text" segment, which is my main() function. Lo and behold, the locations listed by the nm program for my two variables exactly match what was printed when the program ran. (Although there's a complication here; see below.)
Now that we know where the variables actually are, we could draw a slightly different picture:
+---------+ +---------+
10837b018: | 5 | 10837b01c: | 66 |
+---------+ +---------+
^
|
+-------|-------+
10837b020:| * |
+---------------+
This shows us that, basically, the names or identifiers we use for things in our programs — like i, j, ip, and main — are like labels or shorthands for the addresses in memory where these things are stored. (In fact, these identifiers are therefore kind of like pointers in their own right, although I hesitate to say this, because it might confuse the issue.)
Another way to think of it is this. Imagine you live in a large apartment building. In the lobby is a large row of mailboxes, one for each apartment. Each mailbox, naturally, has a label on or next to it giving the apartment number. So the apartment numbers are like addresses, and the contents of the mailbox are like values.
Finally, two footnotes. On a modern system, the nm command probably won't print out addresses that are the same as your program did, after all, due to something called "address space randomization".
When you print pointers, strictly speaking you should cast them to void *, like this:
printf(" i: loc %p, value %d\n", (void *)&i, i);
printf("ip: loc %p, value %p, pointed-to value %d\n", (void *)&ip, (void *)ip, *ip);
C describes abstract machine, where pointer is pointer, and value is value (distinct from pointer).
When it comes to concrete machine, a pointer or a value may be saved in a register (which eliminates the need and the possibility of pointer to it). So you don't have infinite pointer loop, ultimately you have it in a CPU register.
When you compile your program, there may be no correspondence between C code and machine code, especially if optimizations ae enabled, so that &a actually may create creates no pointer (indirection optimized out), whereas b may create a pointer (added indirection to pass large structure).
You are worrying about things that the compiler handles.
When you assign a variable a, the compiler assigns it to a specific memory location or register - the address. The processor knows this address, and using the address, it can access the value of the variable. It doesn't need to keep a separate variable to remember the address.
There are multiple things a processor can do with the address, depending on the operations it supports, but the most common and the most relevant are direct addressing (access the value at the address number given to you in the operation), indirect addressing (access the value at the address number given to you in the operation AND THEN threat that value like an address and access ANOTHER value) and immediate addressing (treat the number given to you as a regular number). Respectively, they match a, *a and &a in C (this is way oversimplified though).
Conclusion - no, creating a pointer won't create an infinite amount of pointers, in order to keep track of the pointers. The processor treats everything the same - addresses are just values and values can be used as addresses.
This is an answer to your comment to S.Ptr answer.
The processor doesn't "know" anything.
The only thing a processor can do is execute instructions: things like "add two numbers together", "put this variable in RAM"... Before modern compiled programming languages like C all programs where created by listing instructions we wanted the processor to execute. A simple addition could have looked like this:
store 10 in memory at address 1
store 5 in memory at address 5
load the value at address 1 into register A
load the value at address 5 into register B
add B to A and store the result in B
store the result of B in memory at address 2
The programmer had to remember where they put everything because the CPU doesn't "understand" what you want it to do, it just follows your commands blindly.
As an example, let's say you made a mistake and you wrote this:
store 10 in memory at address 1
store 5 in memory at address 5
load the value at address 1 into register A
load the value at address 50 into register B
add B to A and store the result in B
store the result of B in memory at address 2
You may hope the CPU will correct you and use the right address but since it doesn't even check for this, the computer will happily run the code and add whatever was at address 50 to 10. When there's only 3 variables it's pretty easy to keep track but as you can guess, the more variables you add, the more difficult it is to remember what memory address corresponds to what data.
To help with this problem, we could use something like "address labels", basically allowing us to write the above code in this way:
please replace all instances of "number1" with "address 1"
please replace all instances of "number2" with "address 5"
please replace all instances of "result" with "address 2"
store 10 in memory at number1
store 5 in memory at number2
load the value at number1 into register A
load the value at number2 into register B
add B to A and store the result in B
store the result of B in memory at result
This way, there's no risk to use the wrong address! "number1", "number2" and "result" are meant to help the programmer so they doesn't have to remember where variables are but since the computer only understand addresses we would need to use a special software to convert the easier to understand code to instructions the machine would actually be able to run.
As time went by, we started creating more and more tools for humans to be able to write better code faster, the C programming language is one on them. Exactly like the "please replace" example, C code helps you avoid mistakes and simplifies programming a lot, at the cost of not being understood by the computer at all.
That's why you need to use a special software called a compiler to run your code, it takes your code and compiles it into the different instructions your dumb computer will execute blindly.
Through the answer I only used pseudo-code so just to get a glimpse at how things work in the real world, let's use some real C code and real CPU assembler. Here's a really simple C code to add two numbers:
int main()
{
int a = 10;
int b = 5;
int result = a + b;
return result;
}
and here's the x86_64 ASM code my compiler created from it:
pushq %rbp
movq %rsp, %rbp
movl $10, -12(%rbp)
movl $5, -8(%rbp)
movl -12(%rbp), %edx
movl -8(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
ret
Note that the ASM listing is still not "raw", it may be a lot more difficult for us to understand than C but it's still too abstract for the CPU.
This minimal program
int r = 100;
return r;
generates just one instruction in main, before the ret:
mov eax,0x64
There is only an immediate and a register. No address. Good nobody asked for it.
With return (long)&r it is (after some stack-checking):
lea eax,[rsp+0x4]
Here there is no value, only the address of where one could (and would) be stored. It's a real living address, but not one containing "100".
Because C's main() returns int, the eax (not rax) is used, and the aligned half of the current stack position (+0x4). The version:
long r = 100;
return &r;
compiles to simply:
mov eax,esp
(i.e. no calculation with lea needed)
To get rid of the different warnings: return (int)(long)&r. This probably shows that addresses are not meant to be returned outside. Here it is only done to force -O3 to do something at all.
So pointers can be created on demand. But in a real program the compiler already has that address stored somewhere / in use.
An infinite pointer "loop" is prevented by:
error: lvalue required as unary '&' operand
6 | return &(&r);
You'd have to put &r into a fresh variable first, before you can take it's address. Fresh variable means new name (or array index) for the programmer and a new memory address ("lvalue") for the compiler.
I finally resolved my confusion(thanks to all the answers) which basically boils down to this.
In real hardware memory, there is a permanent address of each byte of data. At the software level, the operating system creates virtual addresses that map to those real addresses. It's a one-to-one mapping, for one hardware address, there is only one virtual address at a time.
In C, the compiler creates a hashmap-like data structure with variable names as keys and virtual addresses as values. For every new variable, a new entry is added to the hashmap. Whenever we want to get a virtual address of a variable, it's like asking the compiler, "hey, what is the corresponding virtual address associated with this variable name" and the compiler looks through the hashmap and returns the address corresponding to that variable name.
This is just a simplification, as the details are beyond my knowledge, but it nonetheless relieved my confusion for now.
Is there any performance difference when we access a memory location by using a pointer and double pointer?
If so, which one is faster ?
There is no simple answer it, as the answer might depend in the actual machine. If I remember correctly some legacy machines (such as PDP11) offered a 'double pointer' access in a single instruction.
However, this is not the situation today. accessing memory is not as simple as it looks and requires a lot of work, due to virtual memory. For this reason - my guess is that double reference should in fact be slower on most modern machines - more work has to be done to translate two addresses from virtual addresses to physical addresses and retrieving them - but that's just educated guess.
Note however, that the compiler might optimize 'redundant' accesses for you already.
For my best knowledge however, there is no machine that has faster 'double access' than 'single access', so we can say that single access is not worse than double access.
As a side note, I believe in real life programs, the difference is neglectable (comparing to anything else done in the program), and unless done in a very performance sensitive loop - just do whatever is more readable. Also, the compiler might optimize it for you already if it can.
Assuming you are talking about something like
int a = 10;
int *aptr = &a;
int **aptrptr = &aptr;
Then the cost of
*aptr = 20;
Is one dereference. The address pointed to by aptr must first be retrieved and then the address can be stored to.
The cost of
**aptrptr = 30;
Is two dereferences. The address pointed to by aptrptr must first be retrieved. Then the addess stored in that address must be retrieved. Then this address can be stored to.
Is this what you were asking?
Therefore, to conclude using a single pointer is faster if that suits your needs.
Note, that if you access a pointer or double pointer in a loop, for example,
while(some condition)
*aptr = something;
or
while(some condition)
**aptrptr = something;
The compiler will likely optimize so that the dereferencing is only done once at the start of the loop, so the cost is only 1 extra address fetch rather than N, where N is the numnber of times the loop executes.
EDIT:
(1) As Amit correctly points out the "how" of pointer access is not explicitly a C thing... it does depend on the underlying architecture. If your machine supports a double dereference as a single instruction then there might not be a big difference. He is using the index deferred addressing mode of the PDP11 as an example. You might find out that such an instruction still chews up more cycles... consult the hardware documentation and look at the optimization that your C compiler is able to apply for your specific architecture.
The PDP11 architecture is circa the 1970s. As far as I know (if someone knows are modern architecture that can do this pleas post!), most RISC architectures and don't have such a double dereference and will probably need to do two fetches as far as I am aware.
Therefore, to conclude using a single pointer is probably faster generally, but with the caveat that specific architectures may handle this better than others and compiler optimizations, as I discussed, could make the difference negligible... to be sure you just have to profile your code and read up about your architecture :)
Let's see it in this way:
int var = 5;
int *ptr_to_var = &var;
int **ptr_to_ptr = &ptr;
When the variable var is accessed then you need to
1.get the address of the variable
2.fetch its value from that address.
In case of pointer ptr_to_var you need to
1.get the address of the pointer variable
2.fetch its value from that address (i.e, address of the variable var)
3.fetch the value at the address pointed to.
In third case, pointer to pointer to int variable ptr_to_ptr, you need to
1.get the address of the pointer to pointer variable
2.fetch its value from that address (i.e, address of the pointer to variable ptr_var)
3.again fetch its value from the address fetched in the second step(i.e, address of the variable var)
4.fetch the value at the address pointed to.
So we can say that accessing via pointer to pointer variable is slower than that of pointer variable which in turn slower than that of normal variable accessing.
I got curious and set up the following scenario:
int v = 0;
int *pv = &v;
int **ppv = &pv;
I tried dereferencing the pointers and took a look at the disassembly, which showed the following:
int x;
x = *pv;
00B33C5B mov eax,dword ptr [pv]
00B33C5E mov ecx,dword ptr [eax]
00B33C60 mov dword ptr [x],ecx
x = **ppv;
00B33C63 mov eax,dword ptr [ppv]
00B33C66 mov ecx,dword ptr [eax]
00B33C68 mov edx,dword ptr [ecx]
00B33C6A mov dword ptr [x],edx
You can see that there is an additional mov instruction for dereferencing there so my best guess is: double dereferencing is inevitably slower.
In modern processors it is possible to load a register from memory and then post-modify the indexing pointer by a desired value. For example, in our embedded processor, this will be done by:
ldr r0, [r1], +12
which means - load the value pointed to by r1 into r0 and then increment r1 by 12:
r0 = [r1]
r1 = r1 + 12
In the C language, using pointer arithmetics, one can assign a value using a pointer and then advance the pointer by 1:
char i, *p, a[3]={10, 20, 30};
p = &(a[0]);
i = *p++;
// now i==10 and p==&(a[1]).
I am looking for a way to dereference a pointer while post-modifying it by an offset other than 1. Is this possible in C, so it maps nicely to the similar asm instruction?
Note that:
i = *p+=2;
increases the value in a[0] w/o modifying the pointer, and:
i = *(p+=2);
pre-modifies the pointer, so in this case i==30.
Yes this is possible.
You shouldn't be doing weird pointer math to make it happen.
Not only is it about optimization settings, your GCC back-end needs to tell GCC that it has such a feature (i.e. when GCC itself is being compiled). Based on this knowledge, GCC automatically combines the relevant sequence into a single instruction.
i.e. if your back-end is written right, even something like:
a = *ptr;
ptr += SOME_CONST;
should become a single post-modify instruction.
How to correctly set this up when writing a back-end? (ask your friendly neighbourhood GCC back-end developer to do it for you):
If your GCC back-end is called foo:
In the GCC source tree, the back-end description and hooks will be located at gcc/config/foo/.
Among the files there (which get compiled along with GCC), there is usually a header foo.h which contains a lot of #defines describing machine features.
GCC expects that a back-end which supports post-increment define the macro HAVE_POST_INCREMENT to evaluate to true, and if it supports post-modify, then define the macro HAVE_POST_MODIFY_DISP to true. (post-increment => ptr++, post-modify => ptr += CONST). Maybe there are a few other things to be handled as well.
Assuming that your processor's back-end has got this right, lets move to what happens when you compile your code containing said post-modify sequence:
There is a specific GCC optimization pass that goes through instruction pairs that fall into this category and combines them. The source for that pass is here, and has a rather clear description of what GCC will do and how to get it to do it.
But this, in the end, is not in your control as a GCC user. It is in the control of the developer who wrote your GCC back-end. All you should be doing, like the most upvoted comment says, is:
a = *ptr;
ptr += SOME_CONST;
You can do it this way, but don't do it:
i = *((p += 2) - 2);
(not exactly post-modify)
The closest I can think of:
#define POST_INDEX_ASSIGN(lhs, ptr, index) (lhs = *(ptr), (ptr) += (index))
POST_INDEX_ASSIGN(i, p, 2);
i = *p;
p = (unsigned char*)p + 12;
where i is any kind of type and p is a pointer to that type.
If you don't add the typecast, the pointer increment will be done in steps with size == sizeof(*p), which would make the code completely different from the posted assembler.
For example, had p been an int* on a 32-bit system, the pointer would have been incremented 4*12 bytes without the typecast.
Like this link http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Labels-as-Values.html
I can get the memory address of an label, so if I declare a label, get your address, and add your address, i will pass to next instruction? some ilustration >
int main () {
void *ptr;
label:
instruction 1;
instruction 2;
ptr = &&label;
// So if I do it...
ptr = ptr + 1;
// I will get the instruction 2 correct??
Thanks for all answers.
No, I don't think so.
First of, you seem to take the address of a label, which doesn't work. The label is interpreted by the compiler but it does not represent an actual adress in your code.
Second, every statement in C/C++ (in fact any language) can be translated to many machine language instructions, so instruction 1 could be translated to 3, 5, 10 or even more machine instructions.
Third, your pointer points to void. The C compiler does not know how to increment a void pointer. Normally when you increment a pointer, it adds the size of the data type you are pointing to to the address. So incrementing a long-pointer will add 4 bytes; incrementing a char-pointer will add 1 byte. In this case you have a void-pointer, which points to nothing, and thus cannot be incremented.
Fourth, I don't think that all instructions in x86 machine language are represented by the same number of bytes. So you cannot expect from adding something to a pointer that it gets to the next instruction. You might also end up in the middle of the next instruction.
You can't perform arithmetic on a void*, and the compiler wouldn't know what to add to the pointer to have it point to the next 'instruction' anyway - there is no 1 to 1 correspondence between C statement and the machine code emitted by the compiler. Even for CPUs which have a 'regular' instruction set where instructions are the same size (as opposed to something like the x86 where instructions have a variable number of bytes), a single C statement may result in several CPU instructions (or maybe only one - who knows?).
Expanding on an example in the GCC docs, you might be able to get by with something like the following, but it requires a label for each statement you want to target:
void *statements[] = { &&statement1, &&statement2 };
void** ptr;
statement1:
instruction 1;
statement2:
instruction 2;
ptr = statements;
// goto **ptr; // <== this will jump to 'instruction 1'
// goto **(ptr+1); // <== this will jump to 'instruction 2'
Note that the &&label syntax is described under C Extensions section in GCC docs. It's not C, it's GCC.
Plus, void* does not allow pointer arithmetic - it's a catch-all sort of type in C for pointing at anything. The assumption is that the compiler does not know size of the object it points to (but the programmer should :).
Even more, instruction sizes are widely different on different architectures - four bytes on SPARC, but variable length on x86, for example.
I.e. it doesn't work in C. You will have to use inline assembler for this sort of things.
No, because you can't increment void *.
void fcn() { printf("hello, world\n"); }
int main()
{
void (*pt2Function)() = fcn;
pt2Function(); // calls fcn();
// error C2171: '++' : illegal on operands of type 'void (__cdecl *)(void)'
// ++pt2Function;
return 0;
}
This is VC++, but I suspect gcc is similar.
Edited to add
Just for fun, I tried this—it crashed:
int nGlobal = 0;
__declspec(naked) void fcn()
{
// nop is 1-byte instruction that does nothing
_asm { nop }
++nGlobal;
_asm { ret }
}
int main()
{
void (*pt2Function)() = fcn;
// this works, incrementing nGlobal:
pt2Function();
printf("nGlobal: %d", nGlobal);
char *p = (char *) pt2Function;
++p; // point past the NOP?
pt2Function = (void (*)()) p;
// but this crashes...
pt2Function();
printf("nGlobal: %d", nGlobal);
return 0;
}
It crashed because this line doesn't do what I thought it did:
void (*pt2Function)() = fcn;
I thought it would take the address of the first instruction of fcn(), and put it in pt2Function. That way my ++p would make it point to the second instruction (nop is one byte long).
It doesn't. It puts the address of a jmp instruction (found in a big jump table) into pt2Function. When you increment it by one byte, it points to a meaningless location in the jump table.
I assume this is implementation-specific.
I would say "probably not". The value of the pointer will be right, because the compiler knows, but I doubt that the + 1 will know the length of instructions.
Let us suppose there's a way to get the address of a label (that is no an extension of a specific compiler). Then the problem would really be "the next instruction" idea: it can be very hard to know which is the next instruction. It depends on the processor, and on processors like x86 to know the length of an instruction you have to decode it, not fully of course but it is anyway some complex job... on notable RISC architectures, instructions' length is a lot easier and getting the next instruction could be as easy as incrementing the address by 4. But there's no a general way to do it at runtime, while at compile time it could be easier, but to allow it in a C-coherent way, C should have the type "instruction", so that "instruction *" can be a pointer to an instruction, and incrementing such a pointer would point correctly to the next instruction, provided the code is known at compile time (so, such a pointer can't point really to everything pointer can point to in general). At compile time the compiler could implement this feature easily adding another "label" just beyond the generated instruction pointed by the "first" "label". But it would be cheating...
Moreover, let us suppose you get the address of a C label, or C function, or whatever. If you skip the first instruction, likely you won't be able to "use" that address to execute the code (less the first instruction), since without that single instruction the code may become buggy... unless you know for sure you can skip that single instruction and obtain what you want, but you can't be sure... unless you take a look at the code (which can be different from compiler to compiler), and then all the point of doing such a thing from C disappears.
So, briefly, the answer is no, you can't compute the pointer to the next instruction; and if you do someway, the fact that you're pointing to code becomes meaningless since you can't jump to that address and be sure of the final behaviour.