I was learning Go recently. This is something about Go pointer.
Here is the code:
var house = "Malibu Point 10880, 90265"
ptr := &house
fmt.Printf("ptr type: %T \n", ptr)
fmt.Printf("address: %p \n", ptr)
value := *ptr
fmt.Printf("value type: %T \n", value)
fmt.Printf("value: %S\n", value)
fmt.Printf("value: %s\n", value)
The tutorial is coded as line 3 with %s but with %S it gives this strange result:
ptr type: *string
address: 0xc000010200
value type: string
value: %!S(string=Malibu Point 10880, 90265)
value: Malibu Point 10880, 90265
The %s should be the string value of this pointer, but what does %S mean?
%S is not a valid fmt verb. The output you're getting is equivalent to %p. There's nothing special about %S. This appears to happen with any unrecognized verb.
fmt.Printf("value: %p\n", value)
fmt.Printf("value: %S\n", value)
fmt.Printf("value: %L\n", value)
fmt.Printf("value: %A\n", value)
value: %!p(string=Malibu Point 10880, 90265)
value: %!S(string=Malibu Point 10880, 90265)
value: %!L(string=Malibu Point 10880, 90265)
value: %!A(string=Malibu Point 10880, 90265)
This behavior is from badVerb which is called when you give a bad fmt verb. It's documented in "Format errors" in the fmt docs.
Format errors:
If an invalid argument is given for a verb, such as providing a string to %d, the generated string will contain a description of the problem, as in these examples:
Wrong type or unknown verb: %!verb(type=value)
Related
I am writing some bpftrace code in which I would like to compare an IP address (stored as a 32 bit integer) against the string representation of an address. That is, I want to do something like this:
kprobe:netif_receive_skb {
$skb = (struct sk_buff *)arg0;
$dev = $skb->dev;
$name = $dev->name;
$ipheader = ((struct iphdr *) ($skb->head + $skb->network_header));
// This pseudocode conditional is what I am trying to figure out
if ($ipheader->daddr == "8.8.8.8") {
printf("%s %s %s -> %s\n",
func, $name, ntop($ipheader->saddr), ntop($ipheader->daddr))
}
}
In the above, $ipheader is a struct iphdr *, and struct iphdr looks like this:
struct iphdr {
...
__struct_group(/* no tag */, addrs, /* no attrs */,
__be32 saddr;
__be32 daddr;
);
};
So both saddr and daddr are unsigned 32-bit integers.
I thought perhaps I could use the pton() function, like this:
if ($ipheader->daddr == pton("8.8.8.8")) {
But unfortunately pton() returns an int8[4] array instead of a single 32 bit integer, so this fails with:
traceit.bpf:8:5-41: ERROR: Type mismatch for '==': comparing 'unsigned int32' with 'unsigned int8[4]'
if ($ipheader->daddr == pton("8.8.8.8")) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I next tried to see if I could normalize both values into int8[4] arrays, like this:
$target = pton("8.8.8.8");
$daddr = pton(ntop($ipheader->daddr));
if ($target == $daddr) {
But this fails because ntop() doesn't actually return a string, so we get:
ERROR: Expected string literal, got inet
traceit.bpf:9:10-38: ERROR: pton() expects an string argument of an IPv4/IPv6 address, got
$daddr = pton(ntop($ipheader->daddr));
I realize I could just specify the target as an integer myself:
if ($ipheader->daddr == 0x08080808) {
But while that's easy to interpret for a contrived address like 8.8.8.8, it's opaque when the hex form of the address is something like 0xacd9004e.
Is it possible to compare a 32-bit integer representation of an address with the string representation of an address using bpftrace (and if so, what's the canonical way of doing so)?
My Go code:
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
func main() {
fmt.Println(&Point{1, 2})
fmt.Printf("%v\n", &Point{1, 2})
fmt.Printf("%p\n", &Point{1, 2})
}
Output:
&{1 2}
&{1 2}
0xc00002c070
This does not match the documentation in https://godoc.org/fmt. The documentation says,
The default format for %v is:
bool: %t
int, int8 etc.: %d
uint, uint8 etc.: %d, %#x if printed with %#v
float32, complex64, etc: %g
string: %s
chan: %p
pointer: %p
As per the documentation above, for pointers, using %v should behave like using %p.
Why then does the output of fmt.Printf("%v\n", &Point{1, 2}) not match the output of fmt.Printf("%p\n", &Point{1, 2})?
You quoted some part form the fmt package doc, just not "enough". The continuation of your quote:
For compound objects, the elements are printed using these rules, recursively, laid out like this:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2 ...]
pointer to above: &{}, &[], &map[]
*Point is a pointer to struct, thus it is printed using &{field0 field1 ...}.
Pointer to struct is very common in Go, and most of the time when printing it you're not interested in the pointer value but the pointed struct (or the pointed struct's fields). So the fmt package has a rule to print what most would like to see. If you do need the address, you can print it using %p as in your example.
In the following code
var a int
var b interface{}
b = a
fmt.Printf("%T, %T \n", a, &a)
fmt.Printf("%T, %T \n", b, &b)
output:
int, *int
int, *interface {}
I would expect the type of &b to be a pointer on int.
I have two questions:
1) Why is it a pointer on interface{} ?
2) How could I get a pointer on the original type ?
&b => this is the address operator applied on the variable b, whose type is interface{}. So &b will be a pointer of type *interface{}, pointing to the variable b. If you take the address of a variable of type T, the result will always be of type *T.
You cannot obtain the address of the variable a from b, because the assignment:
b = a
Simply copies the value of a into b. It wraps the value of a in an interface value of type interface{}, and stores this interface value into b. This value is completely detached from a.
In general, all assignments copy the values being assigned. There are no reference types in Go. The closest you can get to what you want is if you store the address of a in b in the first place, e.g.:
b = &a
Then you can use type assertion to get out a's address from b like this:
fmt.Printf("%T, %T \n", a, &a)
fmt.Printf("%T, %T \n", b, b.(*int))
This outputs (try it on the Go Playground):
int, *int
*int, *int
(Note: when you simply print b, since it is of an interface type, the fmt package prints the (concrete) value wrapped in it.)
See related questions:
How to get a pointer to a variable that's masked as an interface?
Changing pointer type and value under interface with reflection
Just to complete icza's answer. In case if you don't know the type of the value stored in the interface (and, hence, you can't explicitly use type assertion), you can use reflect package:
var a int
var b interface{}
b = &a
fmt.Println(reflect.TypeOf(b))
I have the following program :
int main()
{
char arr[] = "geeksforgeeks";
char *ptr = arr;
while(*ptr != '\0')
++*ptr++;
printf("%s %s", arr, ptr);
getchar();
return 0;
}
Output: hffltgpshfflt
Explanation given is :
If one knows the precedence and associativity of the operators then there is nothing much left. Below is the precedence of operators.
Postfixx ++ left-to-right
Prefix ++ right-to-left
Dereference * right-to-left
Therefore the expression ++*ptr++ has following effect :
Value of *ptr is incremented
Value of ptr is incremented
My question is how this pointer expression ++*ptr++ is getting implemented and why does this statement "printf("%s %s", arr, ptr);" not printing the string "geeksforgeeks" as well ?
Please help.
Answer to --> why does this statement "printf("%s %s", arr, ptr);" not printing the string "geeksforgeeks" as well ?
Here,array elements of arr are incremented by 1 i.e.,g+1=h,e+1=f.... so on this is getting incremented by 1 due to ++*ptr which increments the ptr value .
ptr++ will incremented by one it means the ptr address is incremented by '1'. until the null character.
So, you are printing arr it shows the value as hffltgpshfflt and printing the ptr which is now pointing to NULL which prints nothing. you can check the ptr value by %x format it prints 0.
For the following line of code I am getting the error below:
for (UILabel *label in labels) {
label.text = label.tag - 100 > someMutableString.length ? "" : "*";
}
The error states:
Implicit conversion of a non-Objective-C pointer type 'char *' to 'NSString *' is disallowed with ARC
My variable "someMutableString" is of type NSMutableString.
How do I fix in my particular case?
The problem is that your string literals are "" and "*" which are both C-style strings (const char*). So the type of the right hand side of the assignment is also const char*. You are assigning to the text property of a UILabel, which takes an NSString.
Use #"" and #"*" instead.
char *text = "a"
NSString *message = [NSString stringWithFormat:#"%s",text];
Cheers :)